ヘッダーをスキップ
Oracle® Database移行ガイド
12cリリース1 (12.1)
B71352-02
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

4 JDBCアプリケーションとODBCアプリケーションのSQL翻訳

この章では、次の項目について説明します。

JDBCアプリケーションのSQL翻訳

この項では、JDBCアプリケーションでSQLトランスレータを使用する場合に理解する必要がある概念について次の各項で説明します。

SQL翻訳プロファイル

SQL翻訳プロファイルは、Oracle以外の言語のSQL文をどのようにOracle SQL言語に翻訳するかを指示するデータベース・スキーマ・オブジェクトです。また、Oracleエラー・コードとSQLSTATESが、他のベンダーのSQL言語に翻訳される方法も指示します。

Oracle以外のSQLデータベース用に作成されたクライアント・アプリケーションをOracleに移行する場合、SQL翻訳プロファイルを作成し、アプリケーションのSQL文とエラーを翻訳するようにそのプロファイルを構成できます。アプリケーションは、そのSQL文とエラーを翻訳するためにOracle Databaseで接続のプロファイルをランタイムで設定します。このプロファイルは、oracle.jdbc.sqlTranslationProfileプロパティを使用して設定されます。

必要に応じて、SQL文とエラーのカスタム翻訳を、サーバーのSQL翻訳プロファイルに登録できます。SQL文やエラーが翻訳されると、最初にカスタム翻訳が調べられ、一致が見つからない場合のみ、トランスレータが起動します。

「SQL翻訳フレームワークのアーキテクチャ」および「SQL翻訳プロファイルの設定」を参照してください。

エラー・メッセージの翻訳

ネイティブ・データベースによってスローされる場合に使用されるメッセージの形式で、エラー・メッセージを受信できます。データベースへの有効な接続がない場合は、エラー・メッセージ翻訳ファイルを使用してエラー・メッセージを翻訳する必要があります。データベースへの接続が確立されると、JDBCドライバはこのファイルを完全にバイパスし、すべてのエラーはサーバー上のトランスレータを使用して行われます。問合せの翻訳と同様に、サーバーにカスタム・エラー翻訳を登録することもできます。

エラー・メッセージ翻訳ファイルは、特定のコンポーネントによって記述されるわけではありません。翻訳するファイルを提供し、ファイル名を指定する必要があります。対応する接続プロパティの値としてファイル・パスを指定することもできます。

エラー・メッセージ翻訳ファイルはXML形式であり、ファイルには一連のエラーの翻訳が含まれています。各エラー翻訳には、次の情報が含まれます。

翻訳エラー タイプ
ORAエラー番号 正の整数
Oracleエラー・メッセージ 文字列
翻訳されたエラー・コード 正の整数
翻訳されたSQL状態 正の整数

JDBC標準パラメータ・マーカーの変換

JDBCドライバは、SQL文を発行して翻訳する前に、JDBC標準パラメータ・マーカー(?)をOracleスタイルのパラメータ・マーカー(形式は:b<n>)に内部で変換します。パラメータ・マーカーの命名形式は:b<n>になります。nは、JDBC PreparedStatementでの(?)マーカーの位置を指定する増分番号です。たとえば、UPDATE employees SET salary = salary * ? WHERE employee_id = ? PreparedStatement文の場合、最初のパラメータ・マーカー(?)は:b1、2番目のパラメータ・マーカー(?)は:b2になります。変換後、ドライバは次の問合せをサーバーに送信して、翻訳を行います。

UPDATE employees SET salary = salary * :b1 WHERE employee_id = :b2

パラメータ・マーカーとしての"?"を含む問合せは、processEscapesプロパティの値をFALSEに変更すると、接続翻訳フェーズで失敗することに注意してください。翻訳が正常に行われるようにするには、processEscapesプロパティのデフォルト値のままにしておく必要があります。

パラメータ・マーカーの変換を行うと、翻訳時に発生したパラメータの変更をドライバが自動的に並び替える場合に役立ちます。変換中に、サーバーにカスタム翻訳を登録する必要がある場合、Oracle形式のパラメータ・マーカーのバージョンから登録してください。そのバージョンで、サーバーは文を受信します。JDBC形式のパラメータ・マーカーのバージョンからは登録しないでください。また、カスタム翻訳では、元の問合せのパラメータ・マーカーと同じ数のOracleスタイルのパラメータ・マーカーが必要です。

サポートされているJDBC APIの詳細は、第8章「JDBCアプリケーションのSQL翻訳のAPIリファレンス」を参照してください。

翻訳したOracle言語問合せの実行

JDBC標準パラメータ・マーカーがOracleスタイルのパラメータ・マーカーに変換されると、ドライバは、問合せをOracle言語に翻訳するためにサーバーに対してラウンドトリップを行います。翻訳された問合せをサーバーが受信すると、パラメータの並替えがドライバによって透過的に処理され、問合せは通常の問合せとして実行されます。

翻訳ができないために問合せの翻訳が不可になる場合、サーバーは、DBMS_SQL_TRANSLATOR.ATTR_RAISE_TRANSLATION_ERRORプロファイル属性の値に基づき、エラーを発生するか、NULLを戻すことができます。サーバーがNULLを戻す場合、翻訳されていない元の問合せが、ドライバによって翻訳される問合せとみなされて実行されます。

ドライバは、ローカル・キャッシュに翻訳を保持して、今後のラウンドトリップを保存します。

JDBCドライバは、DBMS_SQL_TRANSLATOR.ATTR_RAISE_TRANSLATION_ERROR属性のいずれかの値により設定される翻訳エラー(翻訳ができないために問合せが翻訳できない場合)をサポートできます。ただし、この値は、接続が確立される前にサーバー上で設定する必要があります。セッション中にこの属性の値を変更すると、動作の一貫性が保たれない場合があるので、セッション中はこの属性の値を反転しないことをお薦めします。TRANSLATE_SQLプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

エラー翻訳

SQLExceptionが問合せ実行時にスローされた場合、ドライバは、サーバーに透過的に移動し、例外をOracleコードから元のベンダー固有のコードに翻訳します。結果として生じるSQLExceptionには、ベンダー固有のコードとSQLSTATE、およびOracle固有のSQLExceptionが原因として存在します。

問合せ翻訳と同様に、サーバーにカスタム・エラー翻訳を登録して、その翻訳を標準翻訳よりも優先にすることもできます。DBMS_SQL_TRANSLATOR.ATTR_RAISE_TRANSLATION_ERROR属性のカスタム・エラー翻訳と問合せ翻訳に対する効果は同じです。

エラーは、サーバーへの接続が確立された後でしか翻訳されないことに注意してください。そのため、サーバーへの接続が確立される前に発生するエラーの場合、エラー・メッセージの翻訳が使用されます。

JDBCドライバを使用したSQL翻訳

例4-1に、SQL翻訳でのJDBCドライバの使用方法を示します。最初に、次のようにCREATE SQL TRANSLATION PROFILE権限をHRに付与する必要があります。

conn system/manager;
grant create sql translation profile to HR;
exit

HRとしてデータベースに接続し、次のSQL文を実行します。

drop table sample_tab;
create table sample_tab (c1 number, c2 varchar2(100));
insert into sample_tab values (1, 'A');
insert into sample_tab values (1, 'A');
insert into sample_tab values (1, 'A');
commit;
exec dbms_sql_translator.drop_profile('FOO');
exec  dbms_sql_translator.create_profile('FOO');
exec  dbms_sql_translator.register_sql_translation('FOO','select row of select c1, c2 from sample_tab 
where c1=:b1 and c2=:b2','select c1, c2 from sample_tab where c1=:b1 and c2=:b2');

JDBC標準パラメータ・マーカーを使用するSQL文を翻訳する次のプログラムを実行できます。

例4-1 JDBCドライバを使用したOracle以外のSQL文のOracle SQL言語への翻訳

public class SQLTransPstmt 
{
  static String url="jdbc:oracle:thin:@localhost:5521:jvx1";
  static String user="HR", pwd="hr";  
  static String PROFILE = "FOO";
  static String primitiveSql = "select row of select c1, c2 from sample_tab where c1=? and c2=?";
  
// Note that this query contains JDBC style parameter markers
// But the preceding custom translation registered in SQL is using Oracle style markers
 
  public static void main(String[] args) throws Exception
  {       
    OracleDataSource ods = new OracleDataSource();
    ods.setURL(url);
        
    Properties props = new Properties();
    props.put("user", user);
    props.put("password", pwd);
 
    // The Following connection property makes the connection translating    
    props.put(OracleConnection.CONNECTION_PROPERTY_SQL_TRANSLATION_PROFILE, PROFILE);
    ods.setConnectionProperties(props);
    Connection conn = ods.getConnection();
    System.out.println("connection for SQL translation: "+conn);
    
    try{
      // Any statements created using a translating connection are
      // automatically translating. If you want to get a non-translating
      // statement out of a translating connection please have a look at
      // the oracle.jdbc.OracleTranslatingConnection Interface.
      // Refer to "OracleTranslatingConnection Interface"
      // for more information
      PreparedStatement trStmt = conn.prepareStatement(primitiveSql);
      trStmt.setInt(1, 1);
      trStmt.setString(2, "A");      
      System.out.println("executeQuery for: "+primitiveSql);
      ResultSet trRs = trStmt.executeQuery();
      while (trRs.next())
        System.out.println("C1:"+trRs.getInt(1)+", C2:"+trRs.getString(2));
      trRs.close();
      
      trStmt.close();
    }catch (Exception e) {
      e.printStackTrace();
    }
    
    
    conn.close();
  }
}

ODBCアプリケーションのSQL翻訳

この項では、ODBCアプリケーションでSQLトランスレータを使用する場合に把握する必要がある概念について次の各項で説明します。

SQL翻訳プロファイル

ODBCアプリケーションの場合、SQL翻訳プロファイルはサービス・レベルで設定されます。したがって、.odbc.iniファイルで設定する必要はありません。

エラー・メッセージの翻訳

ネイティブ・データベースによってスローされる場合に使用されるメッセージの形式で、エラー・メッセージを受信できます。そのような場合、アプリケーションがOracle Databaseで実行されるよう設定されている際に、ORAエラーをネイティブ・フォームに翻訳するには、.odbc.iniファイルにSQLTranslateErrors=Tエントリを設定する必要があります。

エラー・メッセージの翻訳

例4-2に、SQL翻訳でのODBCドライバの使用方法を示します。この例で使用されるSQL文ではSybase TOP N構文を使用します。

「SQL翻訳フレームワークの使用方法」の項で作成したデータベース・サービス名を使用して.odbc.iniファイルにServerName=エントリを設定する必要があることに注意してください。ネイティブ・データベース・エラーへのOracleエラーの変換が必要な場合は、.odbc.iniファイルにSQLTranslateErros=Tエントリも設定します。

例4-2 ODBCドライバを使用したOracle以外のSQLのOracle SQL言語への翻訳

int main()
{
 HENV m_henv;          /* environment handle */
 HDBC m_hdbc;          /* connection handle */
 HSTMT m_hstmt;        /* statement handle */
 int retCode;          /* return code */
 char dbdsn[100];      /* Initialize with the DSN name of connection */
 const  char szUID[10];/*Initialize with appropriate Username of DB */
 const char szPWD[10]; /* Initialize with appropriate Password */
 
 char query1[100]="select top 3 col1 from babel_tab3 order by col1";
 SQLLEN paramInd = SQL_NTS;
 SQLUINTEGER   no = 0;
 
 //Allocate HENV, HDBC, HSTMT handles
 retCode = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_henv);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
 {
    printf ("SQLAllocHandle failed \n");
    printSQLError (1, m_henv);
 }
 
 retCode = SQLSetEnvAttr (m_henv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3,
           SQL_IS_INTEGER);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
 {
    printf ("SQLSetEnvAttr failed\n");
    printSQLError (1, m_henv);
 }
 
 retCode = SQLAllocHandle (SQL_HANDLE_DBC, m_henv, &m_hdbc);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
 {
    printf ("SQLAllocHandle failed\n");
    printSQLError (2, m_hdbc);
 }
 
 retCode = SQLConnect (m_hdbc, (SQLCHAR *) dbdsn,SQL_NTS,
                       (SQLCHAR *) szUID, SQL_NTS,
                       (SQLCHAR *) szPWD, SQL_NTS);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
 {
    printf ("SQLConnect failed to connect\n");
    printSQLError (2, m_hdbc);
 }
 
 retCode = SQLAllocHandle (SQL_HANDLE_STMT, m_hdbc, &m_hstmt);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
 {
    printf ("SQLAllocHandle with SQL_HANDLE_STMT failed\n");
    printSQLError (3, m_hstmt);
 }
 
 /* Prepare and Execute the Sybase Top-N syntax SQL statements */
 
 retCode = SQLPrepare (m_hstmt, (SQLCHAR *) query1, SQL_NTS);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
 {
    printf ("SQLPrepare failed\n");
    printSQLError (3, m_hstmt);
 }
 
 retCode=SQLExecute(m_hstmt);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
 {
    printf ("SQLExecute-failed\n");
    printSQLError (3, m_hstmt);
 }
 
 while (retCode = SQLFetch(m_hstmt)!=SQL_NO_DATA)
 {
    retCode=SQLGetData(m_hstmt,1,SQL_C_ULONG, &no, 0, &paramInd);
    if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
    {
       printf ("SQLFetch failed\n");
       printSQLError (3, m_hstmt);
    }
    printf("Value is %d\n",no);
 }
 
 retCode = SQLCloseCursor (m_hstmt);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
    printf ("SQLCloseCursor failed\n");
 
 printf ("cleanup()\n");
 retCode = SQLFreeHandle (SQL_HANDLE_STMT, m_hstmt);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
 {
    printf ("SQLFreeHandle failed\n");
    printSQLError (3, m_hstmt);
 }
 
 retCode = SQLDisconnect (m_hdbc);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
 {
    printf ("SQLDisconnect failed\n");
    printSQLError (2, m_hdbc);
 }
 
 retCode = SQLFreeHandle (SQL_HANDLE_DBC, m_hdbc);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
 {
    printf ("SQLFreeHandle failed\n");
    printSQLError (2, m_hdbc);
 }
 
 retCode = SQLFreeHandle (SQL_HANDLE_ENV, m_henv);
 if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
 {
    printf ("SQLFreeHandle failed\n");
    printSQLError (1, m_henv);
 }
}