ヘッダーをスキップ

Oracle Database 管理者リファレンス
10g リリース2(10.2) for UNIX Systems

B19278-06
目次
目次
索引
索引

戻る 次へ

G Oracle ODBC Driverの使用


注意:

Oracle ODBCドライバは、Linux x86、Linux ItaniumおよびSolaris SPARC 64の各プラットフォームに対してのみサポートされます。 


この付録では、Oracle ODBC Driverの使用方法について説明します。次の項目について説明します。

G.1 サポートされていない機能

Oracle ODBC Driverは、次のODBC 3.0機能をサポートしていません。

Oracle ODBC Driverは、次の表に示すSQL関数をサポートしていません。

文字列関数  数値関数  時間関数、日付関数および間隔関数 

BIT_LENGTH 

ACOS 

CURRENT_DATE 

CHAR_LENGTH 

ASIN 

CURRENT_TIME 

CHARACTER_LENGTH 

ATAN 

CURRENT_TIMESTAMP 

DIFFERENCE 

ATAN2 

EXTRACT 

OCTET_LENGTH 

COT 

TIMESTAMPDIFF 

POSITION 

DEGREES

RADIANS

RAND

ROUND 

 

G.2 データ型の実装

この項では、DATETIMESTAMPおよび浮動小数点の各データ型について説明します。

DATEおよびTIMESTAMP

OracleのDATEおよびTIMESTAMPデータ型のセマンティクスは、同名のODBCデータ型と必ずしも正確に対応していません。OracleのDATEデータ型には、日付と時間の両方の情報が格納されています。これに対して、SQL_DATEデータ型に格納されているのは、日付情報のみです。OracleのTIMESTAMPデータ型にも日付と時間の情報が格納されていますが、その小数秒の精度は他方に比較して高くなります。Oracle ODBC Driverは、情報が失われるのを防ぐために、OracleのDATE列とTIMESTAMP列の両方のデータ型をSQL_TIMESTAMPとして報告します。同様に、Oracle ODBC DriverはSQL_TIMESTAMPパラメータをOracleのTIMESTAMP値としてバインドします。

関連項目:

パフォーマンスとチューニングに関するDATEおよびTIMESTAMPデータ型の詳細は、「DATEおよびTIMESTAMPデータ型」を参照してください。 

浮動小数点データ型

リリース10.1以上のOracle Databaseに接続すると、Oracle ODBC Driverは、Oracleの浮動小数点データ型BINARY_FLOATBINARY_DOUBLEをODBCデータ型SQL_REALSQL_DOUBLEにそれぞれマップします。これより前のリリースでは、SQL_REALSQL_DOUBLEがOracleの汎用数値データ型にマップされていました。

G.3 データ型に関する制限事項

Oracle ODBC DriverおよびOracle Databaseには、データ型に関する制限事項があります。次の表に制限事項を示します。

制限があるデータ型  説明 

リテラル 

Oracle Databaseでは、SQL文のリテラルは4000バイトに制限されています。 

SQL_LONGVARCHARおよびSQL_WLONGVARCHAR 

Oracleでは、列型がLONGSQL_LONGVARCHARデータは2,147,483,647バイトに制限されます。また、Oracleでは、列型がCLOBSQL_LONGVARCHARデータは4GBに制限されます。これは、クライアント・ワークステーションのメモリーによる制限です。 

SQL_LONGVARCHARおよびSQL_LONGVARBINARY 

Oracle Databaseで使用できるのは、表ごとに1列のLONGデータ列のみです。LONGデータ型とは、SQL_LONGVARCHARLONG)およびSQL_LONGVARBINARYLONG RAW)です。かわりに、CLOBおよびBLOB列の使用をお薦めします。1つの表で使用できるCLOBおよびBLOBの列数に制限はありません。 

G.4 SQLDriverConnect関数の接続文字列の書式

SQLDriverConnect関数は、Oracle ODBC Driverによって実装される関数の1つです。次の表に、SQLDriverConnect関数コールの接続文字列の引数に含めることができるキーワードを示します。

キーワード  意味   

DSN 

ODBCデータソース名 

ユーザー指定の名前。

これは必須のキーワードです。 

DBQ 

TNSサービス名 

ユーザー指定の名前。

これは必須のキーワードです。 

UID 

ユーザーIDまたはユーザー名 

ユーザー指定の名前。

これは必須のキーワードです。 

PWD 

パスワード 

ユーザー指定の名前。

パスワードがない場合はPWD=;と指定します。

これは必須のキーワードです。 

DBA 

データベース属性 

Wは書込みアクセスを意味します。

Rは読取り専用アクセスを意味します。 

APA 

アプリケーション属性 

Tはスレッド・セーフティを有効にすることを意味します。

Fはスレッド・セーフティを無効にすることを意味します。 

RST 

結果セット 

Tは結果セットを有効にすることを意味します。

Fは結果セットを無効にすることを意味します。 

QTO 

問合せタイムアウト・オプション 

Tは問合せタイムアウトを有効にすることを意味します。

Fは問合せタイムアウトを無効にすることを意味します。 

CSR 

カーソルのクローズ 

Tはカーソルのクローズを有効にすることを意味します。

Fはカーソルのクローズを無効にすることを意味します。 

BAM 

バッチ自動コミット・モード 

IfAllSuccessfulは、すべての文が成功した場合のみコミットすることを意味します(古い動作)。

UpToFirstFailureは、最初に失敗した文までコミットすることを意味します。これはODBCバージョン7の動作です。

AllSuccessfulは、成功したすべての文をコミットすることを意味します。 

FBS 

フェッチ・バッファ・サイズ 

ユーザー指定の数値(0バイト以上の値を指定します)。

デフォルトは60,000バイトです。 

FEN 

フェイルオーバー 

Tはフェイルオーバーを有効にすることを意味します。

Fはフェイルオーバーを無効にすることを意味します。 

FRC 

フェイルオーバー再試行数 

ユーザー指定の数値。

デフォルトは10です。 

FDL 

フェイルオーバーの遅延 

ユーザー指定の数値。

デフォルトは10です。 

LOB 

LOB書込み 

TはLOBを有効にすることを意味します。

FはLOBを無効にすることを意味します。 

FWC 

SQL_WCHAR強制サポート 

TForce SQL_WCHARを有効にすることを意味します。

FForce SQL_WCHARを無効にすることを意味します。 

EXC 

EXEC構文 

TEXEC構文を有効にすることを意味します。

FEXEC構文を無効にすることを意味します。 

XSM 

スキーマ・フィールド 

Defaultはデフォルト値が使用されることを意味します。

Databaseはデータベース名が使用されることを意味します。

Ownerは所有者名が使用されることを意味します。 

MDI 

METADATA IDデフォルトの設定 

TSQL_ATTR_METADATA_IDのデフォルト値がSQL_TRUEであることを意味します。

FSQL_ATTR_METADATA_IDのデフォルト値がSQL_FALSEであることを意味します。 

DPM 

SQLDescribeParamの無効化 

TSQLDescribeParamを無効にすることを意味します。

FSQLDescribeParamを有効にすることを意味します。 

BTD 

TIMESTAMPDATEとしてバインド 

TSQL_TIMESTAMPがOracleのDATEとしてバインドされることを意味します。

FSQL_TIMESTAMPがOracleのTIMESTAMPとしてバインドされることを意味します。 

NUM 

数値の設定 

NLSは、グローバリゼーション・サポートの数値の設定が使用されることを意味します(小数点およびグループのセパレータを判断するため)。 

G.5 プログラムでのロック・タイムアウトの削減

Oracle Databaseは、トランザクション間のロックの競合が解決されるまで無期限に待機します。ただし、Oracle Databaseがロックの解決を待機する時間は制限できます。制限するには、ODBCのSQLSetStmtAttr関数のコール時にSQL_ATTR_QUERY_TIMEOUT属性を設定してから、データソースに接続します。

G.6 ODBCアプリケーションのリンク

プログラムをリンクする場合は、そのプログラムをDriver Managerライブラリlibodbc.soにリンクする必要があります。

G.7 ROWIDに関する情報の取得

ODBCのSQLSpecialColumns関数は、表内の列に関する情報を返します。Oracle ODBC Driverで使用すると、この関数はOracle表に関連付けられたOracle ROWIDに関する情報を返します。

G.8 WHERE句のROWID

ROWIDは、SQL文のWHERE句で使用できます。ただし、ROWID値はパラメータ・マーカー内に存在している必要があります。

G.9 結果セットの有効化

Oracle参照カーソル(結果セットとも呼ばれます)によって、アプリケーションでは、ストアド・プロシージャとストアド・ファンクションを使用してデータを取得できます。ここでは、参照カーソルを使用してODBCを介して結果セットを有効にする方法を説明します。

次のサンプル・アプリケーションは、Oracle ODBC Driverを使用して結果セットを返す方法を示します。

/*
* Sample Application using Oracle reference cursors through ODBC
*
* Assumptions:
*
* 1) Oracle Sample database is present with data loaded for the EMP table.
*
* 2) Two fields are referenced from the EMP table, ename and mgr.
*
* 3) A data source has been setup to access the sample database.
*
*
* Program Description:
*
* Abstract:
*
* This program demonstrates how to return result sets using
* Oracle stored procedures
*
* Details:
*
* This program:
* Creates an ODBC connection to the database.
* Creates a Packaged Procedure containing two result sets.
* Executes the procedure and retrieves the data from both result sets.
* Displays the data to the user.
* Deletes the package then logs the user out of the database.
*
*
* The following is the actual PL/SQL this code generates to
* create the stored procedures.
*  
DROP PACKAGE   ODBCRefCur;
CREATE PACKAGE ODBCRefCur AS
     TYPE ename_cur IS REF CURSOR;
     TYPE mgr_cur   IS REF CURSOR;
PROCEDURE EmpCurs(Ename IN OUT ename_cur, Mgr IN OUT mgr_cur, pjob IN VARCHAR2); 

END; 

/
CREATE PACKAGE BODY ODBCRefCur AS
PROCEDURE EmpCurs(Ename IN OUT ename_cur, Mgr IN OUT mgr_cur, pjob IN VARCHAR2)
     AS
       BEGIN
          IF NOT Ename%ISOPEN
          THEN
              OPEN Ename for SELECT ename from emp;
          END IF; 

          IF NOT Mgr%ISOPEN
          THEN
              OPEN Mgr for SELECT mgr from emp where job = pjob;
          END IF;
       END;
END;
/ 


*
*  End PL/SQL for Reference Cursor. 
*/

/*
 * Include Files
 */
#include <stdio.h>
#include <sql.h>
#include <sqlext.h>
/*
 * Defines
 */
#define JOB_LEN 9
#define DATA_LEN 100
#define SQL_STMT_LEN 500
/*
 * Procedures
 */
void DisplayError( SWORD HandleType, SQLHANDLE hHandle, char *Module );
/*
 * Main Program
 */
int main()
{
SQLHENV hEnv;
SQLHDBC hDbc;
SQLHSTMT hStmt;
SQLRETURN rc;
char *DefUserName ="scott";
char *DefPassWord ="tiger";
SQLCHAR ServerName[DATA_LEN];
SQLCHAR *pServerName=ServerName;
SQLCHAR UserName[DATA_LEN];
SQLCHAR *pUserName=UserName;
SQLCHAR PassWord[DATA_LEN];
SQLCHAR *pPassWord=PassWord;
char Data[DATA_LEN];
SQLINTEGER DataLen;
char error[DATA_LEN];
char *charptr;
SQLCHAR SqlStmt[SQL_STMT_LEN];
SQLCHAR *pSqlStmt=SqlStmt;
char *pSalesMan = "SALESMAN";
SQLINTEGER sqlnts=SQL_NTS;
/*
 * Allocate the Environment Handle
 */
rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv );
if (rc != SQL_SUCCESS)
{
  printf( "Cannot Allocate Environment Handle\n");
  printf( "\nHit Return to Exit\n");
  charptr = gets ((char *)error);
  exit(1);
}
/*
 * Set the ODBC Version
 */
rc = SQLSetEnvAttr( hEnv,SQL_ATTR_ODBC_VERSION,(void *)SQL_OV_ODBC3,0);
if (rc != SQL_SUCCESS)
{
  printf( "Cannot Set ODBC Version\n");
  printf( "\nHit Return to Exit\n");
  charptr = gets ((char *)error);
  exit(1);
}
/*
 * Allocate the Connection handle
 */
rc = SQLAllocHandle( SQL_HANDLE_DBC, hEnv, &hDbc );
if (rc != SQL_SUCCESS)
{
  printf( "Cannot Allocate Connection Handle\n");
  printf( "\nHit Return to Exit\n");
  charptr = gets ((char *)error);
  exit(1);
}
/*
 * Get User Information
 */
strcpy ((char *) pUserName, DefUserName );
strcpy ((char *) pPassWord, DefPassWord );
/*
 * Data Source name
 */
printf( "\nEnter the ODBC Data Source Name\n" );
charptr = gets ((char *) ServerName);
/*
 * User Name
 */
printf ( "\nEnter User Name Default [%s]\n", pUserName);
charptr = gets ((char *) UserName);
if (*charptr == '\0')
{
  strcpy ((char *) pUserName, (char *) DefUserName );
}
/*
 * Password
 */
printf ( "\nEnter Password Default [%s]\n", pPassWord);
charptr = gets ((char *)PassWord);
if (*charptr == '\0')
{
  strcpy ((char *) pPassWord, (char *) DefPassWord );
}
/*
 * Connection to the database
 */
rc = SQLConnect( hDbc,pServerName,(SQLSMALLINT) strlen((char  
*)pServerName),pUserName,(SQLSMALLINT) strlen((char 
*)pUserName),pPassWord,(SQLSMALLINT) strlen((char *)pPassWord));
if (rc != SQL_SUCCESS)
{
  DisplayError(SQL_HANDLE_DBC, hDbc, "SQLConnect");
}
/*
 * Allocate a Statement
 */
rc = SQLAllocHandle( SQL_HANDLE_STMT, hDbc, &hStmt );
if (rc != SQL_SUCCESS)
{
  printf( "Cannot Allocate Statement Handle\n");
  printf( "\nHit Return to Exit\n");
  charptr = gets ((char *)error);
  exit(1);
}
/*
 * Drop the Package
 */
strcpy( (char *) pSqlStmt, "DROP PACKAGE ODBCRefCur");
rc = SQLExecDirect(hStmt, pSqlStmt, strlen((char *)pSqlStmt));
/*
 * Create the Package Header
 */
strcpy( (char *) pSqlStmt, "CREATE PACKAGE ODBCRefCur AS\n");
strcat( (char *) pSqlStmt, " TYPE ename_cur IS REF CURSOR;\n");
strcat( (char *) pSqlStmt, " TYPE mgr_cur IS REF CURSOR;\n\n");
strcat( (char *) pSqlStmt, " PROCEDURE EmpCurs (Ename IN OUT ename_cur,");
strcat( (char *) pSqlStmt, "Mgr IN OUT mgr_cur,pjob IN VARCHAR2);\n\n");
strcat( (char *) pSqlStmt, "END;\n");
rc = SQLExecDirect(hStmt, pSqlStmt, strlen((char *)pSqlStmt));
if (rc != SQL_SUCCESS)
{
  DisplayError(SQL_HANDLE_STMT, hStmt, "SQLExecDirect");
}
/*
 * Create the Package Body
 */
strcpy( (char *) pSqlStmt, "CREATE PACKAGE BODY ODBCRefCur AS\n");
strcat( (char *) pSqlStmt, " PROCEDURE EmpCurs (Ename IN OUT ename_cur,");
strcat( (char *) pSqlStmt, "Mgr IN OUT mgr_cur, pjob IN VARCHAR2)\n AS\n  BEGIN\n");
strcat( (char *) pSqlStmt, " IF NOT Ename%ISOPEN\n THEN\n");
strcat( (char *) pSqlStmt, " OPEN Ename for SELECT ename from emp;\n");
strcat( (char *) pSqlStmt, " END IF;\n\n");
strcat( (char *) pSqlStmt, " IF NOT Mgr%ISOPEN\n THEN\n");
strcat( (char *) pSqlStmt, " OPEN Mgr for SELECT mgr from emp where job = pjob;\n");
strcat( (char *) pSqlStmt, " END IF;\n");
strcat( (char *) pSqlStmt, " END;\n");
strcat( (char *) pSqlStmt, "END;\n");
rc = SQLExecDirect(hStmt, pSqlStmt, strlen((char *)pSqlStmt));
if (rc != SQL_SUCCESS)
{
  DisplayError(SQL_HANDLE_STMT, hStmt, "SQLExecDirect");
}
/*
 * Bind the Parameter
 */
rc = SQLBindParameter(hStmt,1,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,JOB_
LEN,0,pSalesMan,0,&sqlnts);
/*
 * Call the Store Procedure which executes the Result Sets
 */
strcpy( (char *) pSqlStmt, "{CALL ODBCRefCur.EmpCurs(?)}");
rc = SQLExecDirect(hStmt, pSqlStmt, strlen((char *)pSqlStmt));
if (rc != SQL_SUCCESS)
{
  DisplayError(SQL_HANDLE_STMT, hStmt, "SQLExecDirect");
}
/*
 * Bind the Data
 */
rc = SQLBindCol( hStmt,1,SQL_C_CHAR,Data,sizeof(Data),&DataLen);
if (rc != SQL_SUCCESS)
{
  DisplayError(SQL_HANDLE_STMT, hStmt, "SQLBindCol");
}
/*
 * Get the data for Result Set 1
 */
printf( "\nEmployee Names\n\n");
while ( rc == SQL_SUCCESS )
{
  rc = SQLFetch( hStmt );
  if ( rc == SQL_SUCCESS )
  {
    printf("%s\n", Data);
  }
  else
  {
    if (rc != SQL_NO_DATA)
    {
      DisplayError(SQL_HANDLE_STMT, hStmt, "SQLFetch");
    }
  }
}
printf( "\nFirst Result Set - Hit Return to Continue\n");
charptr = gets ((char *)error);
/*
 * Get the Next Result Set
 */
rc = SQLMoreResults( hStmt );
if (rc != SQL_SUCCESS)
{
  DisplayError(SQL_HANDLE_STMT, hStmt, "SQLMoreResults");
}
/*
 * Get the data for Result Set 2
 */
printf( "\nManagers\n\n");
while ( rc == SQL_SUCCESS )
{
  rc = SQLFetch( hStmt );
  if ( rc == SQL_SUCCESS )
  {
    printf("%s\n", Data);
  }
  else
  {
    if (rc != SQL_NO_DATA)
    {
    DisplayError(SQL_HANDLE_STMT, hStmt, "SQLFetch");
    }
  }
}
printf( "\nSecond Result Set - Hit Return to Continue\n");
charptr = gets ((char *)error);
/*
 * Should Be No More Results Sets
 */
rc = SQLMoreResults( hStmt );
if (rc != SQL_NO_DATA)
{
  DisplayError(SQL_HANDLE_STMT, hStmt, "SQLMoreResults");
}
/*
 * Drop the Package
 */
strcpy( (char *) pSqlStmt, "DROP PACKAGE ODBCRefCur");
rc = SQLExecDirect(hStmt, pSqlStmt, strlen((char *)pSqlStmt));
/*
 * Free handles close connections to the database
 */
SQLFreeHandle( SQL_HANDLE_STMT, hStmt );
SQLDisconnect( hDbc );
SQLFreeHandle( SQL_HANDLE_DBC, hDbc );
SQLFreeHandle( SQL_HANDLE_ENV, hEnv );
printf( "\nAll Done - Hit Return to Exit\n");
charptr = gets ((char *)error);
return(0);
}
/*
 * Display Error Messages
 */
void DisplayError( SWORD HandleType, SQLHANDLE hHandle, char *Module )
{
SQLCHAR MessageText[255];
SQLCHAR SQLState[80];
SQLRETURN rc=SQL_SUCCESS;
long NativeError;
SWORD RetLen;
SQLCHAR error[25];
char *charptr;
rc =
SQLGetDiagRec(HandleType,hHandle,1,SQLState,&NativeError,MessageText,255,&RetLen);
printf( "Failure Calling %s\n", Module );
if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
{
  printf( "\t\t\t State: %s\n", SQLState);
  printf( "\t\t\t Native Error: %d\n", NativeError );
  printf( "\t\t\t Error Message: %s\n", MessageText );
}
printf( "\nHit Return to Exit\n");
charptr = gets ((char *)error);
exit(1);
}

G.10 EXEC構文の有効化

使用しているSQL ServerのEXEC文の構文を変更せずに同等のOracleプロシージャ・コールに容易に変換できる場合、その構文は、このオプションを有効にすると、Oracle ODBC Driverで変換できます。

SQL Serverプロシージャの完全な名前は、次に示す最大4つの識別子で構成されます。

この名前の書式は次のとおりです。

[[[server.][database].][owner_name].]procedure_name

Microsoft SQL ServerデータベースからOracle Databaseに移行する際、各SQL Serverプロシージャまたはファンクションの定義は同等のOracle Database構文に変換され、Oracle Databaseのスキーマで定義されます。移行したプロシージャは、多くの場合、次のいずれかの方法で再編成(およびスキーマで作成)されます。

移行したプロシージャを編成するこれら3通りの方法をサポートするためには、いずれかのスキーマ名オプションを指定してプロシージャ名を変換できます。変換したOracleプロシージャ・コールのオブジェクト名では、大/小文字が区別されません。

G.11 サポートされている機能

この項では、Oracle ODBC Driverでサポートされている機能について説明します。次の項目について説明します。

G.11.1 APIへの準拠

Oracle ODBC Driverリリース10.2.0.1.0以上では、コア、レベル2およびレベル1のすべての関数をサポートしています。

G.11.2 ODBC API関数の実装

次の表に、Oracle ODBC Driverが特定の関数を実装する方法を示します。

機能  説明 

SQLConnect 

SQLConnectで必要なのは、DBQ、ユーザーIDおよびパスワードのみです。 

SQLDriverConnect 

SQLDriverConnectでは、DSNDBQUIDおよびPWDの各キーワードが使用されます。 

SQLSpecialColumns 

SQL_BEST_ROWID属性を指定してSQLSpecialColumnsをコールすると、常にROWID列を返します。 

SQLProceduresおよびSQLProcedureColumns 

次の項の説明を参照してください。 

すべてのカタログ関数 

SQL_ATTR_METADATA_ID文の属性がSQL_TRUEに設定されている場合、文字列の引数は、識別子の引数として処理されますが、このケースはあまり重要ではありません。この場合、アンダースコア(_)およびパーセント記号(%)は検索用パターン文字ではなく、実際の文字として処理されます。これに対して、この属性をSQL_FALSEに設定すると、文字列の引数は、通常の引数またはパターン値の引数となり、リテラルに処理されるため、このケースは重要です。 

SQLProceduresおよびSQLProcedureColumns

SQLProceduresコールおよびSQLProcedureColumnsコールは、パッケージ内に含まれている場合でも、すべてのプロシージャおよびファンクションに関する情報を検索して返すように変更されました。これより前のリリースでは、これらのコールで検索されるのは、パッケージ外のプロシージャとファンクションのみでした。次の例では、SQL_ATTR_METADATA_ID属性をSQL_FALSEに設定した場合に返されるプロシージャまたはファンクションを示します。

この例では、次のストアド・プロシージャがあるとします。

"BAR"
"BARX"
"XBAR"
"XBARX"
"SQLPROCTEST.BAR" 
"SQLPROCTEST.BARX" 
"SQLPROCTEST.XBAR" 
"SQLPROCTEST.XBARX" 

%または%%%%%%と指定して検索すると、これら8つのプロシージャがすべて返されます。

%_または_%と指定して検索すると、次のプロシージャが返されます。

BAR 
BARX 
XBAR 
XBARX 

..%%.%SQLPROC%.またはSQLPROC%.%と指定して検索すると、次のプロシージャが返されます。

SQLPROCTEST.BAR
SQLPROCTEST.BARX 
SQLPROCTEST.XBAR 
SQLPROCTEST.XBARX 

%BARと指定して検索すると、次のプロシージャが返されます。

BAR
XBAR

.%BARまたは%.%BARと指定して検索すると、次のプロシージャが返されます。

SQLPROCTEST.BAR
SQLPROCTEST.XBAR 

SQLPROC%または.SQLPROC%と指定して検索すると、次のプロシージャが返されます。

nothing (0 rows)

G.11.3 ODBC SQL構文の実装

比較述語で比較の2番目の式としてパラメータ・マーカーが使用され、そのパラメータの値がSQLBindParameterを使用してSQL_NULL_DATAに設定されている場合、比較は失敗します。これは、ODBC SQLのNULL述語構文と一致しています。

G.11.4 データ型の実装

プログラマがデータ型を実装する際に最も考慮する必要があるのは、CHARVARCHARおよびVARCHAR2の各データ型です。

SQL_VARCHARの値がfSqlTypeの場合、SQLGetTypeInfoはOracle Databaseデータ型VARCHAR2を返します。SQL_CHARの値がfSqlTypeの場合、SQLGetTypeInfoはOracle Databaseデータ型CHARを返します。

G.12 Unicodeのサポート

この項では、Unicodeのサポートについて説明します。次の項目について説明します。

G.12.1 ODBC環境内でのUnicodeのサポート

ODBC Driver Managerを使用すると、すべてのODBCドライバは、Unicodeをサポートしているかどうかに関係なくUnicode準拠と同様に動作します。これによって、ODBCアプリケーションは、基礎となるODBCドライバのUnicode機能に関係なく記述できます。

Driver ManagerがANSI ODBCドライバに対するUnicodeサポートをエミュレートできる範囲は、Unicodeデータとローカル・コード・ページ間で可能な変換内容によって制限されます。Driver ManagerがデータをUnicodeからローカル・コード・ページに変換する際、データが失われる場合があります。基礎となるODBCドライバがUnicodeをサポートしていないかぎり、Unicodeの完全なサポートは不可能です。Oracle ODBC Driverは、Unicodeを完全にサポートしています。

G.12.2 ODBC APIでのUnicodeのサポート

ODBC APIは、WおよびA接尾辞の変換を使用して、UnicodeおよびANSIエントリ・ポイントの両方をサポートします。ODBCアプリケーション開発者は、接尾辞を指定してエントリ・ポイントを明示的にコールする必要はありません。UNICODEおよび_UNICODEプリプロセッサ定義を使用してコンパイルされたODBCアプリケーションによって、適切なコールが生成されます。たとえば、SQLPrepareへのコールは、SQLPrepareWとしてコンパイルされます。

Cデータ型のSQL_C_WCHARがODBCインタフェースに追加されたため、アプリケーションでは、入力パラメータをUnicodeとしてエンコードするように指定するか、またはUnicodeとして返された列データを要求できます。マクロのSQL_C_TCHARは、UnicodeおよびANSIの両方で作成する必要があるアプリケーションで有効です。SQL_C_TCHARマクロは、Unicodeアプリケーションの場合はSQL_C_WCHARとして、ANSIアプリケーションの場合はSQL_C_CHARとしてコンパイルされます。

SQLデータ型のSQL_WCHARSQL_WVARCHARおよびSQL_WLONGVARCHARがODBCインタフェースに追加され、表内で定義された列がUnicodeで表現されるようになりました。これらの値は、SQLDescribeColSQLColAttributeSQLColumnsおよびSQLProcedureColumnsへのコールから返すことも可能です。

Unicodeエンコーディングは、SQL列型のNCHAR、NVARCHAR2およびNCLOBに対してサポートされています。さらに、文字セマンティクスが列定義で指定されている場合、UnicodeエンコーディングはSQL列型のCHARおよびVARCHAR2に対してもサポートされています。

Oracle ODBC Driverは、これらのSQL列型をサポートしてODBC SQLデータ型にマップします。次の表に、サポートされているSQLデータ型および対応するODBC SQLデータ型を示します。

SQLデータ型  ODBC SQLデータ型 

CHAR 

SQL_CHARまたはSQL_WCHAR 

VARCHAR2 

SQL_VARCHARまたはSQL_WVARCHAR 

NCHAR 

SQL_WCHAR 

NVARCHAR2 

SQL_WVARCHAR 

NCLOB 

SQL_WLONGVARCHAR 

G.12.3 SQLGetDataのパフォーマンス

SQLGetData関数を使用すると、ODBCアプリケーションはデータ型を指定して、データのフェッチ後に列を取得できます。OCIでは、Oracle ODBC Driverはデータ型を指定してからフェッチする必要があります。この場合、Oracle ODBC Driverは(データベースで定義された)列のデータ型に関する情報を使用し、OCIを介して列をフェッチする最適なデフォルト方法を判断します。

文字データを含む列がSQLBindColによってバインドされていない場合、Oracle ODBC Driverは、その列をUnicodeとしてフェッチするか、またはローカル・コード・ページとしてフェッチするかを判断する必要があります。ドライバは、列をUnicodeとして受け入れるように常にデフォルト設定できます。ただし、この設定では、2回の不要な変換が実行されます。たとえば、データベース内のデータがANSIとしてエンコードされた場合、データをOracle ODBC DriverにフェッチするためにANSIからUnicodeへの変換が実行されます。次に、ODBCアプリケーションがそのデータをSQL_C_CHARとして要求すると、データを元のエンコーディングに戻すための変換が実行されます。

Oracle Database Clientのデフォルト・エンコーディングは、データをフェッチする際に使用されます。ただし、ODBCアプリケーションでは、このデフォルトを上書きし、列またはパラメータをWCHARデータ型としてバインドすることによって、データをUnicodeとしてフェッチできます。

G.12.4 Unicodeのサンプル

Oracle ODBC Driver自体がTCHARマクロを使用して実装されているため、ODBCアプリケーション・プログラムでは、TCHARを使用して、このドライバを利用することをお薦めします。

次の例では、UNICODEおよび_UNICODEを指定してコンパイルするとWCHARデータ型になるTCHARの使用方法を示します。

例 G-1    データベースへの接続

このコードを使用するには、SQLConnectにUnicodeリテラルのみ指定する必要があります。

HENV         envHnd;
HDBC         conHnd;
HSTMT        stmtHnd;
RETCODE      rc;

rc  = SQL_SUCCESS;

// ENV is allocated
rc = SQLAllocEnv(&envHnd);
// Connection Handle is allocated
rc = SQLAllocConnect(envHnd, &conHnd);
rc = SQLConnect(conHnd, _T("stpc19"), SQL_NTS, _T("scott"), SQL_NTS, _T("tiger"), SQL_
NTS);
.
.
.
if (conHnd)
  SQLFreeConnect(conHnd);
if (envHnd)
  SQLFreeEnv(envHnd);

例 G-2    単純な取得

次の例では、EMP表から従業員名と役職名を取得します。すべてのODBC関数にTCHAR準拠のデータを指定する必要があることを除いて、ANSIの場合と違いはありません。Unicodeアプリケーションの場合は、SQLBindColのコール時にバッファ長をBYTE長に指定する必要があります。たとえば、sizeof(ename)の場合は次のとおりです。

/*
** Execute SQL, bind columns, and Fetch.
** Procedure:
**
**   SQLExecDirect
**   SQLBindCol
**   SQLFetch
** 
*/
static SQLTCHAR *sqlStmt = _T("SELECT ename, job FROM emp");
SQLTCHAR   ename[50];
SQLTCHAR     job[50];
SQLINTEGER enamelen, joblen;
 
_tprintf(_T("Retrieve ENAME and JOB using SQLBindCol 1.../n[%s]/n"), sqlStmt);
 
// Step 1: Prepare and Execute
rc = SQLExecDirect(stmtHnd, sqlStmt, SQL_NTS); // select
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
// Step 2: Bind Columns
rc = SQLBindCol(stmtHnd,
                1,
                SQL_C_TCHAR,
                ename,
                sizeof(ename),
                &enamelen);
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
rc = SQLBindCol(stmtHnd,
                2,
                SQL_C_TCHAR,
                job,
                sizeof(job),
                &joblen);
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
do 
{
  // Step 3: Fetch Data
  rc = SQLFetch(stmtHnd);
  if (rc == SQL_NO_DATA)
    break;
  checkSQLErr(envHnd, conHnd, stmtHnd, rc);
  _tprintf(_T("ENAME = %s, JOB = %s/n"), ename, job);
} while (1);
_tprintf(_T("Finished Retrieval/n/n"));

例 G-3    SQLGetDataを使用した取得(フェッチ後のバインド)

この例では、SQLGetDataの使用方法を示します。Unicode固有の事項に関しては、ANSIアプリケーションとの違いはありません。

/*
** Execute SQL, bind columns, and Fetch.
** Procedure:
**
**   SQLExecDirect
**   SQLFetch
**   SQLGetData
*/
static SQLTCHAR *sqlStmt = _T("SELECT ename,job FROM emp"); // same as Case 1.
SQLTCHAR         ename[50];
SQLTCHAR         job[50];
 
_tprintf(_T("Retrieve ENAME and JOB using SQLGetData.../n[%s]/n"), sqlStmt);
if (rc != SQL_SUCCESS)
{
  _tprintf(_T("Failed to allocate STMT/n"));
  goto exit2;
}
 
// Step 1: Prepare and Execute
rc = SQLExecDirect(stmtHnd, sqlStmt, SQL_NTS); // select
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
do 
{
 
  // Step 2: Fetch
  rc = SQLFetch(stmtHnd);
  if (rc == SQL_NO_DATA)
    break;
  checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
  // Step 3: GetData
  rc = SQLGetData(stmtHnd, 
    1,
    SQL_C_TCHAR,
    (SQLPOINTER)ename,
    sizeof(ename), 
    NULL);
  checkSQLErr(envHnd, conHnd, stmtHnd, rc);
  rc = SQLGetData(stmtHnd, 
    2,
    SQL_C_TCHAR, 
    (SQLPOINTER)job,
    sizeof(job), 
    NULL);
  checkSQLErr(envHnd, conHnd, stmtHnd, rc);
  _tprintf(_T("ENAME = %s, JOB = %s/n"), ename, job);
} while (1);
_tprintf(_T("Finished Retrieval/n/n"));

例 G-4    単純な更新

この例では、データの更新方法を示します。SQLBindParameterのデータ長は、Unicodeアプリケーションの場合でもBYTE長で指定する必要があります。

/*
** Execute SQL, bind columns, and Fetch.
** Procedure:
**
**   SQLPrepare
**   SQLBindParameter
**   SQLExecute
*/
static SQLTCHAR *sqlStmt = _T("INSERT INTO emp(empno,ename,job) VALUES(?,?,?)");
static SQLTCHAR *empno   = _T("9876");      // Emp No
static SQLTCHAR *ename   = _T("ORACLE");    // Name
static SQLTCHAR *job     = _T("PRESIDENT"); // Job
 
_tprintf(_T("Insert User ORACLE using SQLBindParameter.../n[%s]/n"), sqlStmt);
 
// Step 1: Prepare
rc = SQLPrepare(stmtHnd, sqlStmt, SQL_NTS); // select
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
// Step 2: Bind Parameter
rc = SQLBindParameter(stmtHnd, 
                      1, 
                      SQL_PARAM_INPUT,
                      SQL_C_TCHAR,
                      SQL_DECIMAL,
                      4,               // 4 digit
                      0,
                      (SQLPOINTER)empno,
                      0,
                      NULL);
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
rc = SQLBindParameter(stmtHnd, 
                      2, 
                      SQL_PARAM_INPUT,
                      SQL_C_TCHAR,
                      SQL_CHAR,
                      lstrlen(ename)*sizeof(TCHAR),
                      0,
                      (SQLPOINTER)ename,
                      lstrlen(ename)*sizeof(TCHAR),
                      NULL);
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
rc = SQLBindParameter(stmtHnd, 
                      3, 
                      SQL_PARAM_INPUT,
                      SQL_C_TCHAR,
                      SQL_CHAR,
                      lstrlen(job)*sizeof(TCHAR),
                      0,
                      (SQLPOINTER)job,
                      lstrlen(job)*sizeof(TCHAR),
                      NULL);
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
// Step 3: Execute
rc = SQLExecute(stmtHnd);
checkSQLErr(envHnd, conHnd, stmtHnd, rc);

例 G-5    長いデータ(CLOB)の更新と取得

ここでは、CLOBなどの長いデータをOracle Databaseで更新および取得する最も複雑な例を示します。データ長は常にBYTE長であるため、BYTE長を導出するには式lstrlen(TCHAR data)*sizeof(TCHAR)が必要です。

/*
** Execute SQL, bind columns, and Fetch.
** Procedure:
**
**   SQLPrepare
**   SQLBindParameter
**   SQLExecute
**   SQLParamData
**   SQLPutData
**
**   SQLExecDirect
**   SQLFetch
**   SQLGetData
*/
static SQLTCHAR *sqlStmt1  = _T("INSERT INTO clobtbl(clob1) VALUES(?)");
static SQLTCHAR *sqlStmt2  = _T("SELECT clob1 FROM clobtbl");
SQLTCHAR         clobdata[1001];
SQLTCHAR         resultdata[1001];
SQLINTEGER       ind = SQL_DATA_AT_EXEC;
SQLTCHAR        *bufp;
int              clobdatalen, chunksize, dtsize, retchklen;
 
_tprintf(_T("Insert CLOB1 using SQLPutData.../n[%s]/n"), sqlStmt1);
 
// Set CLOB Data
{
  int i;
  SQLTCHAR ch;
  for (i=0, ch=_T('A'); i< sizeof(clobdata)/sizeof(SQLTCHAR); ++i, ++ch)
  {
    if (ch > _T('Z'))
      ch = _T('A');
    clobdata[i] = ch;
  }
  clobdata[sizeof(clobdata)/sizeof(SQLTCHAR)-1] = _T('/0');
}
clobdatalen = lstrlen(clobdata);  // length of characters
chunksize   = clobdatalen / 7;    // 7 times to put

// Step 1: Prepare
rc = SQLPrepare(stmtHnd, sqlStmt1, SQL_NTS);
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
// Step 2: Bind Parameter with SQL_DATA_AT_EXEC
rc = SQLBindParameter(stmtHnd, 
                      1, 
                      SQL_PARAM_INPUT,
                      SQL_C_TCHAR,
                      SQL_LONGVARCHAR,
                      clobdatalen*sizeof(TCHAR),
                      0,
                      (SQLPOINTER)clobdata,
                      clobdatalen*sizeof(TCHAR),
                      &ind);
checkSQLErr(envHnd, conHnd, stmtHnd, rc); 
// Step 3: Execute
rc = SQLExecute(stmtHnd);
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
// Step 4: ParamData (initiation)
rc = SQLParamData(stmtHnd, (SQLPOINTER*)&bufp); // set value
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
for (dtsize=0, bufp = clobdata;
     dtsize < clobdatalen;
     dtsize += chunksize, bufp += chunksize)
{
  int len;
  if (dtsize+chunksize<clobdatalen)
    len = chunksize;
  else
    len = clobdatalen-dtsize;
 
  // Step 5: PutData
  rc = SQLPutData(stmtHnd, (SQLPOINTER)bufp, len*sizeof(TCHAR));
  checkSQLErr(envHnd, conHnd, stmtHnd, rc);
}
 
// Step 6: ParamData (temination)
rc = SQLParamData(stmtHnd, (SQLPOINTER*)&bufp);
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
rc = SQLFreeStmt(stmtHnd, SQL_CLOSE);
_tprintf(_T("Finished Update/n/n"));
rc = SQLAllocStmt(conHnd, &stmtHnd);
if (rc != SQL_SUCCESS)
{
  _tprintf(_T("Failed to allocate STMT/n"));
  goto exit2;
}
 
// Clear Result Data
memset(resultdata, 0, sizeof(resultdata));
chunksize   = clobdatalen / 15;   // 15 times to put
 
// Step 1: Prepare
rc = SQLExecDirect(stmtHnd, sqlStmt2, SQL_NTS); // select
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
// Step 2: Fetch
rc = SQLFetch(stmtHnd);
checkSQLErr(envHnd, conHnd, stmtHnd, rc);
 
for(dtsize=0, bufp = resultdata;
    dtsize < sizeof(resultdata)/sizeof(TCHAR) && rc != SQL_NO_DATA;
    dtsize += chunksize-1, bufp += chunksize-1)
{
  int len; // len should contain the space for NULL termination
  if (dtsize+chunksize<sizeof(resultdata)/sizeof(TCHAR))
    len = chunksize;
  else
    len = sizeof(resultdata)/sizeof(TCHAR)-dtsize;
 
  // Step 3: GetData
  rc = SQLGetData(stmtHnd, 
    1,
    SQL_C_TCHAR,
    (SQLPOINTER)bufp,
    len*sizeof(TCHAR), 
    &retchklen);
}
if (!_tcscmp(resultdata, clobdata))
{
  _tprintf(_T("Succeeded!!/n/n"));
}
else
{
  _tprintf(_T("Failed!!/n/n"));
}

G.13 パフォーマンスとチューニング

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

G.13.1 ODBCプログラミングの一般的なガイドライン

ODBCアプリケーションのパフォーマンスを向上させるには、次のプログラミング・ガイドラインを適用してください。

G.13.2 データソース構成オプション

この項では、次のODBCデータソース構成オプションを使用した場合のパフォーマンスへの影響を説明します。

G.13.3 DATEおよびTIMESTAMPデータ型

WHERE句でデータベースのDATE列が使用され、その列に索引がある場合は、パフォーマンスに影響を与える可能性があります。たとえば、次のように入力します。

SELECT * FROM EMP WHERE HIREDATE = ?

この例では、HIREDATE列の索引を使用して、問合せを迅速に実行できます。ただし、HIREDATEDATE値で、Oracle ODBC Driverはこのパラメータ値をTIMESTAMPとして提供しているため、Oracle Databaseの問合せオプティマイザは変換関数を適用する必要があります。誤った結果(パラメータ値に0以外の小数秒がある場合に発生する可能性があります)を防ぐために、オプティマイザは、HIREDATE列に変換を適用するため、次のような文になります。

SELECT * FROM EMP WHERE TO_TIMESTAMP(HIREDATE) = ?

ただし、この場合はHIREDATE列で索引を使用できなくなります。かわりに、サーバーでは表の順次スキャンを実行します。したがって、表に多数の行がある場合は時間がかかる可能性があります。このような場合の次善策として、Oracle ODBC DriverにはTIMESTAMPDATEとしてバインドする接続オプションが用意されています。このオプションを有効にすると、Oracle ODBC Driverは、SQL_TIMESTAMPパラメータをOracleのTIMESTAMPデータ型ではなくOracleのDATEデータ型としてバインドします。これによって、問合せオプティマイザはDATE列で索引を使用できます。


注意:

このオプションは、DATE列をTIMESTAMP列としてバインドするMicrosoft Accessや類似のプログラムで使用することを目的にしています。実際のTIMESTAMP列がある場合、またはデータが失われる可能性がある場合は使用しないでください。Microsoft Accessでは、主キーとして選択されたすべての列を使用してこの問合せを実行します。 


G.14 エラー・メッセージ

エラーが発生すると、Oracle ODBC Driverは、システム固有のエラー番号、SQLSTATE(ODBCエラー・コード)およびエラー・メッセージを返します。ドライバは、ドライバが検出したエラーおよびOracle Databaseから返されたエラーの両方からこれらの情報を導出します。

システム固有のエラー

データソースでエラーが発生した場合、Oracle ODBC Driverは、Oracle Databaseから返されたシステム固有のエラーを返します。Oracle ODBC DriverまたはDriver Managerがエラーを検出した場合、Oracle ODBC Driverはシステム固有のエラー番号として0(ゼロ)を返します。

SQLSTATE

データソースでエラーが発生した場合、Oracle ODBC Driverは、返されたシステム固有のエラーを適切なSQLSTATEにマップします。Oracle ODBC DriverまたはDriver Managerがエラーを検出した場合は、適切なSQLSTATEを生成します。

エラー・メッセージ

データソースでエラーが発生した場合、Oracle ODBC Driverは、Oracle Databaseから返されたメッセージに基づいてエラー・メッセージを返します。Oracle ODBC DriverまたはDriver Managerでエラーが発生した場合、Oracle ODBC Driverは、SQLSTATEに関連付けられたテキストに基づいてエラー・メッセージを返します。

エラー・メッセージの書式は次のとおりです。

[vendor] [ODBC-component] [data-source] error-message

大カッコ([ ])内の接頭辞によって、エラーの発生場所を識別します。次の表に、Oracle ODBC Driverから返される接頭辞の値を示します。データソースでエラーが発生した場合は、vendorおよびODBC-component接頭辞によって、データソースからエラーを受け取ったODBCコンポーネントのベンダーと名前を識別します。

エラーの発生場所  接頭辞   

Driver Manager 

[vendor]

[ODBC-component]

[data-source] 

[unixODBC]

[Driver Manager]

該当なし 

Oracle ODBC Driver 

[vendor]

[ODBC-component]

[data-source] 

[ORACLE]

[Oracle ODBC Driver]

該当なし 

Oracle Database 

[vendor]

[ODBC-component]

[data-source] 

[ORACLE]

[Oracle ODBC Driver]

[Oracle OCI] 

たとえば、次の書式に示すように、エラー・メッセージにOra接頭辞が付いていない場合、そのエラーはOracle ODBC Driverのエラーであることがわかります。

[Oracle][ODBC]Error message text here

また、次の書式に示すように、エラー・メッセージにOra接頭辞が付いている場合、このエラーはOracle ODBC Driverのエラーではありません。

[Oracle][ODBC][Ora]Error message text here


注意:

エラー・メッセージにOra接頭辞が付いている場合でも、実際のエラーは複数のソースのいずれかで発生している場合があります。 


エラー・メッセージのテキストがORA-接頭辞で始まっている場合、そのエラーの詳細はOracle Databaseのドキュメントを参照してください。


戻る 次へ
Oracle
Copyright © 2006, 2009, Oracle and/or its affiliates.
All Rights Reserved.
目次
目次
索引
索引