Oracle Call Interface (OCI)とは、リレーショナル・データベース・マネジメント・システムのAPIであり、CまたはC++言語で作成するアプリケーションからデータベース操作を実行することができる。
OCIがサポートするRDBMSとして、OracleデータベースとOracle TimesTen In-Memoryデータベースがある。
OCIアプリケーションは、
oci.h
ヘッダファイルをインクルードする必要がある。
#include <oci.h>
OCIアプリケーションは、OCIライブラリとリンクする必要がある。
ハンドル とは、OCIライブラリによって割り当てられる記憶領域を指す不透明なポインタである。OCIライブラリは、このハンドルを利用してコンテキストや接続などに関する情報にアクセスする。
OCIのハンドル・タイプを表す識別子がヘッダファイル
oci.h
で定義されている。OCIのハンドル・タイプを次の表に示す。
ハンドル・タイプ | 説明 | データ型 |
---|---|---|
OCI_HTYPE_ENV |
環境ハンドル | OCIEnv * |
OCI_HTYPE_ERROR |
エラー・ハンドル | OCIError * |
OCI_HTYPE_SVCCTX |
サービス・コンテキスト・ハンドル | OCISvcCtx * |
OCI_HTYPE_STMT |
文ハンドル | OCIStmt * |
OCI_HTYPE_BIND |
バインド・ハンドル | OCIBind * |
OCI_HTYPE_DEFINE |
定義ハンドル | OCIDefine * |
OCI関数の戻り値や引数のデータ型がヘッダファイルで定義されている。
データ型 | 説明 |
---|---|
sb2 |
符号あり2バイト整数 |
ub2 |
符号なし2バイト整数 |
sb4 |
符号あり4バイト整数 |
ub4 |
符号なし4バイト整数 |
sword |
符号ありワード |
text |
文字 |
OraText |
文字 |
dvoid |
void |
OCI関数の戻り値のデータ型は
sword
である。OCI関数の戻り値を表す識別子がヘッダファイル
oci.h
で定義されている。OCI関数の戻り値を次の表に示す。
戻り値 | 意味 | 診断情報 |
---|---|---|
OCI_SUCCESS |
正常に終了した | なし |
OCI_SUCCESS_WITH_INFO |
正常に終了した | あり |
OCI_NO_DTATA |
これ以上のデータなし | なし |
OCI_ERROR |
失敗した | あり |
OCI_INVALID_HANDLE |
無効なハンドルがパラメータとして渡された | なし |
OCI_NEED_DATA |
アプリケーションからランタイムデータを渡す必要がある | なし |
診断情報がある場合は、OCIErrorGet
関数をコールすることで診断情報を得ることができる。
外部データ型(データベースのデータ型)と、それに対応するプログラム変数のデータ型およびOCI定数との関係を次の表に示す。
外部データ型 | プログラム変数 | OCI定義の定数 |
---|---|---|
VARCHAR2 |
char[
n
] |
SQLT_CHR |
NUMBER |
unsigned char[21] |
SQLT_NUM |
8ビット符号付きINTEGER | signed char |
SQLT_INT |
16ビット符号付きINTEGER | signed short, signed int |
SQLT_INT |
32ビット符号付きINTEGER | signed int, signed long |
SQLT_INT |
FLOAT | float, double |
SQLT_FLT |
ヌル文字で終了するSTRING | char[
n+1] |
SQLT_STR |
OCIアプリケーションのサンプル・ソースコードを次に示す。
#include <oci.h>
#include <stdio.h>
#include <string.h>
void error_handler(sword ociret, dvoid *hndlp)
{
sb4 errcode;
char buf[256];
switch (ociret) {
case OCI_SUCCESS:
break;
case OCI_SUCCESS_WITH_INFO:
printf("OCI_SUCCESS_WITH_INFO\n");
break;
case OCI_NO_DATA:
printf("OCI_NO_DATA\n");
break;
case OCI_ERROR:
printf("OCI_ERROR\n");
OCIErrorGet(hndlp, 1, NULL, &errcode, buf, sizeof(buf), OCI_HTYPE_ERROR);
printf("%d %s\n", errcode, buf);
break;
case OCI_INVALID_HANDLE:
printf("OCI_INVALID_HANDLE\n");
break;
case OCI_NEED_DATA:
printf("OCI_NEED_DATA\n");
break;
default:
break;
}
}
int main()
{
sword ociret;
OCIEnv *envhp;
OCIError *errhp;
OCISvcCtx *svchp;
OCIStmt *stmtp;
OCIBind *bindp;
OCIDefine *dfnp1, *dfnp2;
char *username = "scott";
char *password = "tiger";
char *db_name = "XE";
char *stmt = "SELECT empno, ename FROM emp WHERE deptno = :1";
int empno, deptno = 3;
char ename[64];
/* 環境の作成 */
ociret = OCIEnvCreate(&envhp, OCI_DEFAULT, 0, 0, 0, 0, 0, 0);
error_handler(ociret, envhp);
/* エラー・ハンドルの割り当て */
ociret = OCIHandleAlloc(envhp, &errhp, OCI_HTYPE_ERROR, 0, 0);
error_handler(ociret, errhp);
/* ログイン・セッションの作成 */
ociret = OCILogon(envhp, errhp, &svchp, username, strlen(username),
password, strlen(password), db_name, strlen(db_name));
error_handler(ociret, errhp);
/* 文ハンドルの割り当て */
ociret = OCIHandleAlloc(envhp, &stmtp, OCI_HTYPE_STMT, 0, 0);
error_handler(ociret, errhp);
/* SQL文の準備 */
ociret = OCIStmtPrepare(stmtp, errhp, stmt, strlen(stmt),
OCI_NTV_SYNTAX, OCI_DEFAULT);
error_handler(ociret, errhp);
/* プレースホルダのバインド */
ociret = OCIBindByPos(stmtp, &bindp, errhp, 1, &deptno, sizeof(deptno),
SQLT_INT, 0, 0, 0, 0, 0, OCI_DEFAULT);
error_handler(ociret, errhp);
/* 出力変数の定義 */
ociret = OCIDefineByPos(stmtp, &dfnp1, errhp, 1, &empno, sizeof(empno),
SQLT_INT, 0, 0, 0, OCI_DEFAULT);
error_handler(ociret, errhp);
/* 出力変数の定義 */
ociret = OCIDefineByPos(stmtp, &dfnp2, errhp, 2, ename, sizeof(ename),
SQLT_CHR, 0, 0, 0, OCI_DEFAULT);
error_handler(ociret, errhp);
/* 準備済みのSQL文を実行 */
ociret = OCIStmtExecute(svchp, stmtp, errhp, 1, 0, NULL, NULL, OCI_DEFAULT);
error_handler(ociret, errhp);
while (OCI_SUCCESS == ociret) {
printf("%d %s\n", empno, ename);
/* 結果セットから行をフェッチ */
ociret = OCIStmtFetch2(stmtp, errhp, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
error_handler(ociret, errhp);
}
/* 文ハンドルの解放 */
ociret = OCIHandleFree(stmtp, OCI_HTYPE_STMT);
error_handler(ociret, errhp);
/* ログイン・セッションの解放 */
ociret = OCILogoff(svchp, errhp);
error_handler(ociret, errhp);
/* エラー・ハンドルの解放 */
ociret = OCIHandleFree(errhp, OCI_HTYPE_ERROR);
error_handler(ociret, errhp);
}
OCI環境を利用するプログラムは、まずOCI環境を作成して環境ハンドルを得る必要がある。OCI環境を作成するには、OCIEnvCreate
関数をコールする。
OCIには様々な種類のハンドルが存在する。これらのハンドルを割り当てるには、OCIHandleAlloc
関数をコールする。ただし、環境ハンドルだけは
OCIHandleAlloc
関数ではなく、OCIEnvCreate
関数で割り当てる。
プログラムにおいてどのようなハンドルが必要になるかはコールするOCI関数によって異なるが、絶対必要な環境ハンドルに加えて、エラー・ハンドルやサービス・コンテキスト・ハンドルはほぼ必須となるだろう。
サーバー接続とセッションの確立を行なうには、複数の方法がある。
あるデータベース接続に対して、ひとつのユーザー・セッションしか必要ない場合、OCILogon
関数をコールする。
ひとつのデータベースに対して複数のユーザー・セッションが接続する必要がある場合、OCIServerAttach
および
OCISessionBegin
関数をコールする。
SQL文を発行してデータの処理を行なう基本的な手順を次に示す。
SQL文を実行する前に、SQL文の準備を行なう必要がある。SQL文の準備を行なうには、OCIStmtPrepare
関数をコールする。
OCIアプリケーションから変数の値をSQL文へ渡す場合、プレースホルダのバインドを行なう必要がある。
バインド とは、プログラム変数のアドレスとSQL文(またはPL/SQLブロック内)のプレースホルダを関連付けることである。プレースホルダのバインドを行なうには、次の5種類のOCI関数のうちいずれかをコールする。
OCIBindByName
OCIBindByPos
OCIBindObject
OCIBindDynamic
OCIBindArrayOfStruct
OCIアプリケーションから変数の値をSQL文に渡さない場合、プレースホルダのバインドは行わない。
問い合せ文はデータベースのデータをアプリケーションに戻す。SELECT文などの問い合わせを処理するときには、データを検索する各選択リスト項目について、それぞれ出力変数を定義する必要がある。
出力変数を定義するには、次のOCI関数のうちいずれかをコールする。
OCIDefineByPos
OCIDefineObject
OCIDefineDynamic
OCIDefineArrayOfStruct
準備済みのSQL文を実行するには、OCIStmtExecute
関数をコールする。
SQL文の実行で問い合わせを行なった場合、続けて結果セットのフェッチ(取り出し)を行なう。フェッチを行なうにはOCIStmtFetch2
関数をコールする。
OCILogon
によりログイン・セッションを作成した場合は、OCILogoff
関数をコールしてログイン・セッションを解放する。
割り当てたハンドルを解放するには、OCIHandleFree
関数をコールする。
OCIでトランザクションのコミットやロールバックを行なう場合、
COMMIT
や
ROLLBACK
などのSQL文を発行するのではなく、専用のOCI関数をコールする。
コミットおよびロールバックに関するOCI関数を次に示す。
OCI関数 | 説明 |
---|---|
OCITransCommit | トランザクションをコミットする。 |
OCITransRollback | トランザクションをロールバックする。 |
プログラム変数とSQL文のプレースホルダを名前によって関連付ける。
sword OCIBindByName (
OCIStmt *stmtp,
OCIBind **bindpp,
OCIError *errhp,
CONST text *placeholder,
sb4 placeh_len,
dvoid *valuep,
sb4 value_sz,
ub2 dty,
dvoid *indp,
ub2 *alenp,
ub2 *rcodep,
ub4 maxarr_len,
ub4 *curelep,
ub4 mode,
);
OCIBindByNameのサンプル・ソースコードを次に示す。
sword ociret;
OCIError *errhp;
OCIStmt *stmtp;
OCIBind *bindp;
char *stmt = "SELECT empno, ename FROM emp WHERE deptno = :dept_no";
int deptno = 3;
char *placeholder = "dept_no";
/* 中略 */
ociret = OCIBindByName(stmtp, &bindp, errhp, placeholder, strlen(placeholder),
&deptno, sizeof(deptno), SQLT_INT, 0, 0, 0, 0, 0, OCI_DEFAULT);
プログラム変数とSQL文(またはPL/SQLブロック内)のプレースホルダを位置によって関連付ける。
sword OCIBindByPos (
OCIStmt *stmtp,
OCIBind **bindpp,
OCIError *errhp,
ub4 position,
dvoid *valuep,
sb4 value_sz,
ub2 dty,
dvoid *indp,
ub2 *alenp,
ub2 *rcodep,
ub4 maxarr_len,
ub4 *curelep,
ub4 mode,
);
sword ociret;
OCIError *errhp;
OCIStmt *stmtp;
OCIBind *bindp;
char *stmt = "SELECT empno, ename FROM emp WHERE deptno = :1";
int deptno = 3;
/* 中略 */
ociret = OCIBindByPos(stmtp, &bindp, errhp, 1, &deptno, sizeof(deptno),
SQLT_INT, 0, 0, 0, 0, 0, OCI_DEFAULT);
選択リスト内の項目を型と出力データ・バッファに関連付ける。
sword OCIDefineByPos (
OCIStmt *stmtp,
OCIDefine **dfnpp,
OCIError *errhp,
ub4 position,
dvoid *valuep,
sb4 value_sz,
ub2 dty,
dvoid *indp,
ub2 *rlenp,
ub2 *rcodep,
ub4 mode
);
empno
の位置が1、
ename
の位置が2となる。
sword ociret;
OCIError *errhp;
OCIStmt *stmtp;
OCIDefine *dfnp1, *dfnp2;
int empno;
char ename[64];
/* 中略 */
ociret = OCIDefineByPos(stmtp, &dfnp1, errhp, 1, &empno, sizeof(empno),
SQLT_INT, 0, 0, 0, OCI_DEFAULT);
ociret = OCIDefineByPos(stmtp, &dfnp2, errhp, 2, ename, sizeof(ename),
SQLT_CHR, 0, 0, 0, OCI_DEFAULT);
OCI環境を作成する。
sword OCIEnvCreate (
OCIEnv **envhpp,
ub4 mode,
CONST dvoid *ctxp,
CONST dvoid *(*malocfp)(dvoid *ctxp, size_t size),
CONST dvoid *(*ralocfp)(dvoid *ctxp, dvoid *memptr, size_t newsize),
CONST void (*mfreefp)(dvoid *ctxp, dvoid *memptr),
size_t *tramemsz,
dvoid **usermempp
);
値 | 説明 |
---|---|
OCI_DEFAULT | デフォルト値 |
OCI_THREADED | マルチスレッド環境アプリケーションで使用する |
OCI_OBJECT | オブジェクト機能を使用する |
他のすべてのOCI関数に先立って最初にコールする必要がある。
sword ociret;
OCIEnv *envhp;
ociret = OCIEnvCreate(&envhp, OCI_DEFAULT, 0, 0, 0, 0, 0, 0);
エラー・メッセージとOracleエラーを戻す。
sword OCIErrorGet (
dvoid *hndlp,
ub4 recordno,
text *sqlstate,
sb4 *errcodep,
text *bufp,
ub4 bufsiz,
ub4 type
);
OCIEnvCreate
およびOCIHandleAlloc
の診断情報を得る場合には環境ハンドル。その他のOCI関数の診断情報を得る場合はエラー・ハンドル。
値 | 説明 |
---|---|
OCI_HTYPE_ENV | 環境ハンドル |
OCI_HTYPE_ERROR | エラー・ハンドル |
あらかじめ他のOCI関数をコールしておく必要がある。
sword ociret;
OCIError *errhp;
sb4 errcode;
char buf[256];
/* 中略 */
switch (ociret) {
case OCI_ERROR:
OCIErrorGet(errhp, 1, NULL, &errcode, buf, sizeof(buf), OCI_HTYPE_ERROR);
break;
}
各種ハンドルを割り当てる(環境ハンドルを除く)。
sword OCIHandleAlloc (
CONST dvoid *parenth,
dvoid **hndlpp,
ub4 type,
size_t *tramem_sz,
dvoid **usrmempp
);
type | 説明 | データ型 |
---|---|---|
OCI_HTYPE_ERROR |
エラー・ハンドル | OCIError |
OCI_HTYPE_SERVER |
サーバー・ハンドル | OCIServer |
OCI_HTYPE_STMT |
文ハンドル | OCIStmt |
OCI_HTYPE_SVCCTX |
サービス・コンテキスト・ハンドル | OCISvcCtx |
あらかじめOCIEnvCreate
関数をコールして環境ハンドルを得ておく必要がある。
sword ociret;
OCIEnv *envhp;
OCIError *errhp;
/* 中略 */
ociret = OCIHandleAlloc(envhp, &errhp, OCI_HTYPE_ERROR, 0, 0);
ハンドルの割り当てを明示的に解放する。
sword OCIHandleFree (
dvoid *hndlp,
ub4 type
);
値 | 説明 |
---|---|
OCI_HTYPE_ENV |
環境ハンドル |
OCI_HTYPE_ERROR |
エラー・ハンドル |
OCI_HTYPE_SERVER |
サーバー・ハンドル |
OCI_HTYPE_STMT |
文ハンドル |
OCI_HTYPE_SVCCTX |
サービス・コンテキスト・ハンドル |
sword ociret;
OCIError *errhp;
/* 中略 */
ociret = OCIHandleFree(errhp, OCI_HTYPE_ERROR);
OCILogon
を使用して作成したログイン・セッションを解放する。
sword OCILogoff (
OCISvcCtx *svchp,
OCLError *errhp
);
あらかじめOCILogon
関数をコールしてログイン・セッションを作成しておく必要がある。
sword ociret;
OCIError *errhp;
OCISvcCtx *svchp;
/* 中略 */
ociret = OCILogoff(svchp, errhp);
ログイン・セッションを作成する。
sword OCILogon (
OCIEnv *envhp,
OCIError *errhp,
OCISvcCtx **svchp,
CONST OraText *username
ub4 uname_len,
CONST OraText *password,
ub4 passwd_len,
CONST OraText *dbname,
ub4 dbname_len
);
NULL
を指定した場合、デフォルトのデータベースに接続する。
あらかじめOCIEnvCreate
関数をコールして環境ハンドルを得ておく必要がある。
あらかじめOCIHandleAlloc
関数をコールしてエラー・ハンドルを得ておく必要がある。
sword ociret;
OCIEnv *envhp;
OCIError *errhp;
OCISvcCtx *svchp;
char *username = "scott";
char *password = "tiger";
char *db_name = "XE"
/* 中略 */
ociret = OCILogon(envhp, errhp, &svchp, username, strlen(username),
password, strlen(password), db_name, strlen(db_name));
データ・ソースへのアクセス・パスを作成する。
sword OCIServerAttach (
OCIServer *srvhp,
OCLError *errhp,
CONST text *dblink,
sb4 dblink_len,
ub4 mode
);
値 | 意味 |
---|---|
OCI_DEFAULT | デフォルト |
OCI_CPOOL | 接続プーリングを使用する |
準備済みのSQL文を実行する。
sword OCIStmtExecute (
OCISvcCtx *svchp,
OCIStmt *stmtp,
OCLError *errhp,
ub4 iters,
ub4 rowoff,
CONST OCISnapShot *snap_in,
OCISnapShot *snap_out,
ub4 mode
);
あらかじめOCIStmtPrepare
関数をコールしてSQL文を準備しておく必要がある。
sword ociret;
OCIError *errhp;
OCISvcCtx *svchp;
OCIStmt *stmtp;
/* 中略 */
ociret = OCIStmtExecute(svchp, stmtp, errhp, 1, 0, NULL, NULL, OCI_DEFAULT);
結果セットから行をフェッチする。
sword OCIStmtFetch2 (
OCIStmt *stmtp,
OCLError *errhp,
ub4 nrows,
ub2 orientation,
sb4 fetchOffset,
ub4 mode
);
値 | 意味 |
---|---|
OCI_DEFAULT |
OCI_FETCH_NEXT と同じ |
OCI_FETCH_CURRENT |
現在行を取得 |
OCI_FETCH_NEXT |
現在位置の次の行を取得 |
OCI_FETCH_PRIOR |
現在行の前の行を取得 |
OCI_FETCH_FIRST |
結果セットの最初の行を取得 |
OCI_FETCH_LAST |
結果セットの最後の行を取得 |
OCI_FETCH_ABSOLUTE |
結果セットの行番号を絶対値で指定して取得 |
OCI_FETCH_RELATIVE |
結果セットの行番号を相対値で指定して取得 |
orientation
引数に
OCI_FETCH_ABSOLUTE
または
OCI_FETCH_RELATIVE
を指定した場合、
fetchOffset
パラメータでオフセットを指定する。
sword ociret;
OCIError *errhp;
OCIStmt *stmtp;
/* 中略 */
while (OCI_SUCCESS == ociret) {
ociret = OCIStmtFetch2(stmtp, errhp, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
}
実行するSQL文またはPL/SQL文を準備する。
sword OCIStmtPrepare (
OCIStmt *stmtp,
OCLError *errhp,
CONST text *stmt,
ub4 stmt_len,
ub4 language,
ub4 mode
);
Parameter | I/O | Description |
---|---|---|
stmtp | I | 文ハンドル |
errhp | I | エラーハンドル |
stmt | I | 実行されるSQL文またはPL/SQL文 |
stmt_len | I | 文の長さ。エンコーディングにより文字数またはバイト数の単位になる。 |
language | I | OCI_NTV_SYNTAXを指定する。 |
mode | I | OCI_DEFAULTを指定する。 |
あらかじめOCIHandleAlloc
関数をコールして、文ハンドルおよびエラー・ハンドルを得ておく必要がある。
OCIBindByPos
でプレースホルダをバインドする場合の例
sword ociret;
OCIError *errhp;
OCIStmt *stmtp;
char *stmt = "SELECT empno, ename FROM emp WHERE deptno = :1";
/* 中略 */
ociret = OCIStmtPrepare(stmtp, errhp, stmt, strlen(stmt),
OCI_NTV_SYNTAX, OCI_DEFAULT);
OCIBindByName
でプレースホルダをバインドする場合の例
sword ociret;
OCIError *errhp;
OCIStmt *stmtp;
char *stmt = "SELECT empno, ename FROM emp WHERE deptno = :dept_no";
/* 中略 */
ociret = OCIStmtPrepare(stmtp, errhp, stmt, strlen(stmt),
OCI_NTV_SYNTAX, OCI_DEFAULT);
トランザクションを明示的にコミットする。
sword OCITransCommit (
OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags
);
現在のランザクションをロールバックする。
sword OCITransRollback (
void *svchp,
OCIError *errhp,
ub4 flags
);