7月 162014
 
11月 222013
 

ODACの11g、12cにはOracle.ManagedDataAccessというのが追加されており、ネイティブコードが無くなったのでサーバー環境へのデプロイ時にODP.NETやOracleClientのインストールが不要になる!ということで、やり方を調べてみたメモ。

参考:oracle – Deploying and Configuring ODP.NET to work without installation with Entity Framework – Stack Overflow

これのBのパターンでうまく行った。

  • WCFサービスのホストプロジェクトなどDB接続が必要になるプロジェクトの参照にEntityFramewrokとOracle.ManagedDataAccessを追加し、ローカルコピーをTrueに
  • Web.config/App.configを以下のように設定
<configuration>
  <configSections>
    <section name="oracle.manageddataaccess.client"
      type="OracleInternal.Common.ODPMSectionHandler, Oracle.ManagedDataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
  </configSections>

  <connectionStrings>
    <add name="Entities" connectionString="metadata=res://*/Models.ORCL.csdl|res://*/Models.ORCL.ssdl|res://*/Models.ORCL.msl;provider=Oracle.ManagedDataAccess.Client;provider connection string="data source=exampleserver:1521/ORCL;password=example;user id=example"" providerName="System.Data.EntityClient" />
  </connectionStrings>

  <system.data>
    <DbProviderFactories>
      <remove invariant="Oracle.ManagedDataAccess.Client" />
      <add name="ODP.NET, Managed Driver"
           invariant="Oracle.ManagedDataAccess.Client"
           description="Oracle Data Provider for .NET, Managed Driver"
           type="Oracle.ManagedDataAccess.Client.OracleClientFactory, Oracle.ManagedDataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
    </DbProviderFactories>
  </system.data>

  <oracle.manageddataaccess.client>
    <version number="*">
      <edmMappings>
        <edmMapping dataType="number">
          <add name="bool" precision="1"/>
          <add name="byte" precision="2" />
          <add name="int16" precision="5" />
        </edmMapping>
      </edmMappings>
    </version>
  </oracle.manageddataaccess.client>
  • 適当にデプロイ

Oracle.ManagedDataAccessDTC.dll が必要な場合

  • TransactionScope を使う場合など、Oracle.ManagedDataAccessDTC.dll が必要な時がある
    • 無いと実行時にFileNotFoundExceptionで死ぬ
  • Oracle.ManagedDataAccess.dllと同様に、実行パスかGACに入ってればOK
  • Microsoft Visual C++ 2010 SP1 再頒布可能パッケージ を必要とする点に注意 (SP1じゃなくても大丈夫だとは思うが…)
    • これも同様に、インストールされていないと実行時にFileNotFoundExceptionで死ぬ
  • Oracle.ManagedDataAccessDTC.dll も Microsoft Visual C++ 2010 SP1 再頒布可能パッケージ も32bit版と64bit版があるので、実行環境に合わせたものを使おう
7月 182012
 

Download Oracle Application Express

Oracle Application Express 4.0 Install Guide インストールガイド

4.1.1を使う場合、翻訳バージョンのインストールの際
ALTER SESSION SET CURRENT_SCHEMA = APEX_040000;
の部分は以下のようにする必要がある。
[sql]ALTER SESSION SET CURRENT_SCHEMA = APEX_040100;[sql]
バージョンに応じて適宜変更する必要があると考えられる。

7月 132012
 
  • JDBC APIではPreparedStatementインタフェースを用いてパラメタライズドクエリを実行する
  • OracleJDBCドライバではOraclePreparedStatementクラスを用いてパラメタライズドクエリを実行する
  • OraclePreparedStatementのsetStringメソッドおよびsetCharメソッドは空白埋めを行わない
  • OraclePreparedStatementのsetFixedCharメソッドは空白埋めを行う
  • JDBCのPreparedStatementインタフェースにはsetCharおよびsetFixedCharメソッドは定義されていない
    (これらはOracleのJDBC拡張機能を用いる事で実装できる)

要するに・・・

CHAR(5)型のCOL1列を持ったテーブルTABLE_Aに対して
SELECT * FROM TABLE_A WHERE COL1=?
というSQLに比較文字列をバインドしてを発行する時、setString(1, "ABC")とするとCOL1='ABC'という比較がされ、確実に0件。
setString(1, "ABC ")としなければならない。

OracleParameterdStatement.setFixedChar(int, String)を使用することにより、空白埋め比較でバインドする事も出来るが、DBに依存したコードとなる。

ちなみにバインドをしないでリテラルで比較するとヒットする。
SELECT * FROM TABLE_A WHERE COL1='ABC'
これはOracleでは両辺にVARCHAR2型またはNVARCHAR2型が使用されている場合以外は、空白埋めで比較が行われるためである。

そもそも可変文字列の格納にCHAR型を使うのをやめればすむ話。。

参考:

7月 132012
 
  • Oracle10gのJDBCは、DATE型項目の場合java.sql.Date型で返却するために時刻が欠落する。
  • Oracle9.0.1より前のJDBCではjava.sql.Timestamp型で返却していたため時刻は欠落しない。
  • Oracle11gもjava.sql.Timestamp型で返却する仕様をデフォルトとしているため時刻は欠落しない。

  • Oracle10gの場合、oracle.jdbc.V8Compatible=trueを指定することでjava.sql.Timestamp型で返却する動作となる。

参考:

Oracleオブジェクト型からSQL DATEデータ型へのマッピング

Oracle Database 8i以下のバージョンではTIMESTAMPデータがサポートされていませんでしたが、SQL標準への拡張機能として、Oracle DATEデータに時刻コンポーネントが含まれていました。このため、Oracle Database 8i以下のバージョンのJDBCドライバは、oracle.sql.DATEをjava.sql.Timestampにマップして時刻コンポーネントを保持していました。Oracle Database 9.0.1以上ではTIMESTAMPがサポートされ、9iのJDBCドライバがoracle.sql.DATEをjava.sql.Dateにマッピングするようになりました。このマッピングはOracle DATEデータの時刻コンポーネントを切り捨てたため、不正確でした。この問題を克服するために、Oracle Database 11.1では新しいフラグmapDateToTimestampが導入されました。このフラグのデフォルト値はtrueです。これは、デフォルトで、ドライバがoracle.sql.DATEをjava.sql.Timestampに正確にマップして時刻情報を保持することを意味します。不正確でも10gと互換性のあるoracle.sql.DATEからjava.sql.Dateへのマッピングが必要な場合は、mapDateToTimestampフラグの値をfalseに設定します。

注意:
oracle.sql.DATEからjava.sql.Dateへのマッピングの問題を克服するために、Oracle Database 9.2でフラグV8Compatibleが導入されました。このフラグのデフォルト値はfalseで、これはOracle DATEデータのjava.sql.Dateデータへのマッピングが許可されることを意味します。ただし、このフラグの値をtrueに設定することによって、ユーザーはOracle DATEデータの時刻コンポーネントを保持することができました。このフラグは11gでは非推奨です。これは、Oracle Database 8iとの互換性がサポートされなくなったためです。

Oracleからの回答:

QUESTION
======
oracle.jdbc.V8Compatible=trueにすることで getObject()の戻り値の型がDate→Timestamp と変更される以外に動作が変わることがあるか。

ANSWER
======
ございません。

oracle.jdbc.V8Compatible=true に設定することによる動作の変更点はgetObject()の戻り値の型が Date→Timestamp と変更されるだけでございます。

7月 132012
 

DBへの型のマッピングは気をつけないとダメだよという話。

予備知識とか
  • ANSI SQLのDATE型は日付のみ保持する。
  • OracleのDATE型は日付だけでなく時刻まで保持する。(秒未満の精度とタイムゾーンは保持しない)
DATE型@Java
  • java.sql.DateクラスはANSI準拠。日付までしか保持しない
  • java.util.Dateクラスはミリ秒まで保持する。
  • JDBCではjava.sql.DateクラスはDATE型(JDBC)にマッピングされる。
  • JDBCではjava.util.DateクラスはDATE、TIME、TIMESTAMP型(JDBC)にマッピングされる。
問題例とか
  • JavaでOracleに日付を登録する場合、やり方によっては時刻情報が落ちる。
  • java.sql.Dateのコンストラクタはlong型なミリ秒を受け取れるが、残るのは日付のみ。

参考:

7月 122012
 

OracleSQLでは/**/の開始文字と終了文字は空白や改行でテキストから切り離す必要は無いが、SQL*Plusでは空けなければならない。

Oracle SQLの基本要素

  • スラッシュとアスタリスク(/*)を使用してコメントを開始します。コメントのテキストを続けます。このテキストは複数行にまたがってもかまいません。アスタリスクとスラッシュ(*/)を使用してコメントを終了します。開始文字と終了文字は、空白や改行によってテキストから切り離す必要はありません。
  • –(ハイフン2個)を使用してコメントを開始します。コメントのテキストを続けます。このテキストは複数行にまたがることはできません。改行によってコメントを終了します。

SQLの入力に使用するツール製品には、追加の制限事項があるものもあります。たとえば、SQL*Plusを使用している場合、デフォルトでは複数行のコメント内に空白行を入れることはできません。詳細は、データベースのインタフェースとして使用するツール製品のドキュメントを参照してください。

SQL*Plusでのスクリプトの使用

SQLのコメント・デリミタ(/*…*/)は、スクリプト内の個別の行に入力するか、SQLコマンドと同じ行に入力するか、またはPL/SQLブロック内の行に入力します。

コメントの初めのスラッシュとアスタリスク(/*)の後に空白を入力する必要があります。

コメントは、次のように複数の行にわたっていてもかまいませんが、コメント内にコメントをネストさせることはできません。

/* Commission Report
 to be run monthly. */
COLUMN LAST_NAME HEADING 'LAST_NAME';
COLUMN SALARY HEADING 'MONTHLY SALARY' FORMAT $99,999;
COLUMN COMMISSION_PCT HEADING 'COMMISSION %' FORMAT 90.90;
REMARK Includes only salesmen;
SELECT LAST_NAME, SALARY, COMMISSION_PCT
FROM EMP_DETAILS_VIEW
/* Include only salesmen.*/
WHERE JOB_ID='SA_MAN';