ダイレクト・パス・ロード関数は、データを外部ファイルから表とパーティションにロードするために使用します。
この章は、次の項目で構成されています。
ダイレクト・パス・ロード・インタフェースを使用すると、OCIアプリケーションからOracleデータベース・サーバーのダイレクト・パス・ロード・エンジンにアクセスし、Oracle SQL*Loaderユーティリティの関数を実行できます。この機能によって、データを外部ファイルから表またはパーティション表のパーティションのいずれかにロードできます。
図13-1「ダイレクト・パス・ロード」では、この章のテーマを紹介しています。
OCIダイレクト・パス・ロード・インタフェースには、複数行のデータが含まれたダイレクト・パス・ストリームをロードすることによって複数の行をロードする機能があります。
ダイレクト・パスAPIを使用するには、クライアント・アプリケーションで次のステップを実行します。
OCI初期化を実行します。
ダイレクト・パス・コンテキスト・ハンドルを割り当てて、属性を設定します。
ロードするオブジェクト(表、パーティションまたはサブパーティション)の名前を指定します。
オブジェクトの列の外部データ型を記述します。
ダイレクト・パス・インタフェースを準備します。
1列以上の列配列を割り当てます。
1つ以上のダイレクト・パス・ストリームを割り当てます。
列配列内のエントリを、各列に対する入力データ値を指し示すように設定します。
列配列をダイレクト・パス・ストリーム形式に変換します。
ダイレクト・パス・ストリームをロードします。
発生したエラーをすべて取り出します。
ダイレクト・パス終了関数をコールします。
ハンドルおよびデータ構造を解放します。
サーバーから切断します。
ステップ8〜11は、ロード対象のデータに従って繰り返すことができます。
ダイレクト・ロード操作では、ロードされているオブジェクトをロックしてそのオブジェクトにDMLが実行されないようにする必要があります。オブジェクトのロード中、問合せはロック解除され許可されていることに注意してください。DMLロックのモード、および取得されるDMLロックの種類は、OCI_ATTR_DIRPATH_PARALLELオプションの指定によって決まります。また、表全体をロードするのか、パーティションまたはサブパーティションをロードするのかによっても異なります。
表のロードの場合、OCI_ATTR_DIRPATH_PARALLELオプションの設定とその結果は、次のとおりです。
FALSEの場合、表DML X-Lockが取得されます。
TRUEの場合、表DML S-Lockが取得されます。
パーティションのロードの場合、OCI_ATTR_DIRPATH_PARALLELオプションの設定とその結果は、次のとおりです。
FALSEの場合、表DML SX-LockとパーティションDML X-Lockが取得されます。
TRUEの場合、表DML SS-LockとパーティションDML S-Lockが取得されます。
ダイレクト・パス・ロード操作では、スカラー列に対して有効な外部データ型は次のとおりです。
SQLT_CHR
SQLT_DAT
SQLT_INT
SQLT_UIN
SQLT_FLT
SQLT_BIN
SQLT_NUM
SQLT_PDN
SQLT_DATE
SQLT_TIMESTAMP
SQLT_TIMESTAMP_TZ
SQLT_TIMESTAMP_LTZ
SQLT_INTERVAL_YM
SQLT_INTERVAL_DS
次の外部オブジェクトのデータ型がサポートされています。
SQLT_NTY− 列オブジェクト(FINALとNOT FINAL)およびSQL文字列の列
SQLT_REF−REF列(FINALとNOT FINAL)
次の表の型がサポートされています。
ネストした表
オブジェクト表(FINALとNOT FINAL)
ダイレクト・パス・ロードは、ダイレクト・パス配列の挿入操作に対応しています。ダイレクト・パス・ロード・インタフェースでは、次のハンドルを使用してロードされるオブジェクトおよび操作するデータの指定が記録されます。
ダイレクト・パス・コンテキスト
ダイレクト・パス関数コンテキスト
ダイレクト・パス列配列
ダイレクト・パス関数コンテキストの列配列
ダイレクト・パス・ストリーム
このハンドルは、ロード対象の各オブジェクト(表またはパーティション表のパーティションのいずれか)に対して割り当てる必要があります。OCIDirPathCtxハンドルは、OCIDirPathFuncCtx、OCIDirPathColArrayおよびOCIDirPathStreamハンドルの親ハンドルであるため、OCIDirPathCtxハンドルを解放すると、その子ハンドルも解放されます(ただし、親ハンドルの解放前に、子ハンドルを個別に解放するコーディングをお薦めします)。
ダイレクト・パス・コンテキストは、OCIHandleAlloc()を使用して割り当てます。ダイレクト・パス・コンテキストの親ハンドルは、常に環境ハンドルです。ダイレクト・パス・コンテキストは、OCIHandleFree()を使用して解放します。すべてのダイレクト・パス・プログラムの最初の2行にヘッダー・ファイルを組み込みます。
...
#include <cdemodp0.h>
#include <cdemodp.h>
OCIEnv *envp;
OCIDirPathCtx *dpctx;
sword error;
error = OCIHandleAlloc((void *)envp, (void **)&dpctx,
OCI_HTYPE_DIRPATH_CTX, (size_t)0,(void **)0);
...
error = OCIHandleFree(dpctx, OCI_HTYPE_DIRPATH_CTX);
OCIDirPathFuncCtx型のこのハンドルは、次の名前付き型とREF列の記述に使用します。
列オブジェクト。このオブジェクト内の関数コンテキストでは、オブジェクト型が記述され、デフォルト・コンストラクタとして使用されて、オブジェクトとそのコンストラクタのオブジェクト属性を作成します。
REF列。この列内の関数コンテキストでは、行オブジェクトの参照元である単一のオブジェクト表(オプション)および行オブジェクトを識別するREF引数が記述されます。
SQL文字列の列。この列内の関数コンテキストでは、列にロードする値を計算するためのSQL文字列とその引数が記述されます。
関数コンテキストの割当てを示すには、次の例のようにOCI_HTYPE_DIRPATH_FN_CTXハンドル型をOCIHandleAlloc()に渡します。
OCIDirPathCtx *dpctx; /* direct path context */
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
sword error;
error = OCIHandleAlloc((void *)dpctx, (void **)&dpfnctx,
OCI_HTYPE_DIRPATH_FN_CTX,
(size_t)0, (void **)0);
ダイレクト・パス関数コンテキストの親ハンドルは、常にダイレクト・パス・コンテキスト・ハンドルであることに注意してください。ダイレクト・パス関数コンテキスト・ハンドルは、次のコードで解放します。
error = OCIHandleFree(dpfnctx, OCI_HTYPE_DIRPATH_FN_CTX);
ダイレクト・パス・インタフェースに行配列を表示するには、ダイレクト・パス列配列およびダイレクト・パス関数列配列ハンドルを使用します。行は、列の値、列の長さおよび列フラグの3つの配列によって表します。列配列で使用するメソッドには、配列ハンドルの割当て、および配列のエントリに対応する値の設定や取得があります。
これらのハンドルは同じデータ構造体OCIDirPathColArrayを共有します。ただし、この2つの列配列ハンドルは、親ハンドルとハンドル型が異なります。
ダイレクト・パス列配列ハンドルは、OCIHandleAlloc()を使用して割り当てます。次のコード・フラグメントは、ダイレクト・パス列配列ハンドルの明示的な割当てを示します。
OCIDirPathCtx *dpctx; /* direct path context */
OCIDirPathColArray *dpca; /* direct path column array */
sword error;
error = OCIHandleAlloc((void *)dpctx, (void **)&dpca,
OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
(size_t)0, (void **)0);
ダイレクト・パス列配列ハンドルは、OCIHandleFree()を使用して解放します。
error = OCIHandleFree(dpca, OCI_HTYPE_DIRPATH_COLUMN_ARRAY);
ダイレクト・パス関数列配列ハンドルも、ほとんど同じ方法で割り当てます。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
OCIDirPathColArray *dpfnca; /* direct path function column array */
sword error;
error = OCIHandleAlloc((void *)dpfnctx, (void **)&dpfnca,
(ub4)OCI_HTYPE_DIRPATH_FN_COL_ARRAY,
(size_t)0, (void **)0);
ダイレクト・パス関数列配列ハンドルは、OCIHandleFree()を使用して解放します。
error = OCIHandleFree(dpfnca, OCI_HTYPE_DIRPATH_FN_COL_ARRAY);
OCIDirPathColArrayハンドルの解放により、そのハンドルに関連付けられた列配列も解放されます。
変換操作OCIDirPathColArrayToStream()およびロード操作OCIDirPathLoadStream()には、このハンドルを使用します。
ダイレクト・パス・ストリーム・ハンドルは、クライアントがOCIHandleAlloc()を使用して割り当てます。OCIDirPathStreamハンドルの構造体は、フォーム(バッファ、バッファ長)内のペアとみなすことができます。
ダイレクト・パス・ストリームは、Oracle表データの線形表現です。変換操作は、常にストリームの最後に追加されます。ロード操作は、常にストリームの最初に起動します。ストリームのロードが正常終了した後、OCIDirPathStreamReset()をコールしてストリームをリセットする必要があります。
次のコードは、OCIHandleAlloc()を使用して割り当てられるダイレクト・パス・ストリーム・ハンドルの例です。親ハンドルは、常にOCIDirPathCtxハンドルです。
OCIDirPathCtx *dpctx; /* direct path context */
OCIDirPathStream *dpstr; /* direct path stream */
sword error;
error = OCIHandleAlloc((void *)dpctx, (void **)&dpstr,
OCI_HTYPE_DIRPATH_STREAM, (size_t)0,(void **)0);
ダイレクト・パス・ストリーム・ハンドルは、OCIHandleFree()を使用して解放します。
error = OCIHandleFree(dpstr, OCI_HTYPE_DIRPATH_STREAM);
OCIDirPathStreamハンドルの解放によって、そのハンドルに関連付けられているストリーム・バッファも解放されます。
この項にリストされた関数は、ダイレクト・パス・ロード・インタフェースとともに使用します。
ダイレクト・パス・コンテキストの操作は、表13-1の関数で実行します。
表13-1 ダイレクト・パス・コンテキストの関数
| 関数 | 用途 |
|---|---|
|
|
ダイレクト・パス処理を異常終了します。 |
|
|
データのセーブポイントを実行します。 |
|
|
ロードされたデータをコミットします。 |
|
|
サーバーから部分的にロードされた行をフラッシュします。この関数は非推奨です。 |
|
|
ダイレクト・パス・ストリーム形式に変換されたデータをロードします。 |
|
|
行の変換またはロードを行うために、ダイレクト・パス・インタフェースを準備します。 |
ダイレクト・パス列配列の操作は、表13-2「ダイレクト・パス列配列の関数」の関数で実行します。
表13-2 ダイレクト・パス列配列の関数
| 関数 | 用途 |
|---|---|
|
|
列配列内の特定のエントリを取得します。 |
|
|
列配列内の特定のエントリを特定の値に設定します。 |
|
|
特定の行番号の基本行ポインタを取得します。 |
|
|
行配列の状態をリセットします。 |
|
|
列配列形式からダイレクト・パス・ストリーム形式に変換します。 |
ダイレクト・パス・ストリームの操作は、ダイレクト・ストリームの状態をリセットするOCIDirPathStreamReset()関数で実行します。
次に、スカラー列のコード例を示します。
例では、次のデータ構造が使用されています。
/* load control structure */
struct loadctl
{
ub4 nrow_ctl; /* number of rows in column array */
ub2 ncol_ctl; /* number of columns in column array */
OCIEnv *envhp_ctl; /* environment handle */
OCIServer *srvhp_ctl; /* server handle */
OCIError *errhp_ctl; /* error handle */
OCIError *errhp2_ctl; /* yet another error handle */
OCISvcCtx *svchp_ctl; /* service context */
OCISession *authp_ctl; /* authentication context */
OCIParam *colLstDesc_ctl; /* column list parameter handle */
OCIDirPathCtx *dpctx_ctl; /* direct path context */
OCIDirPathColArray *dpca_ctl; /* direct path column array handle */
OCIDirPathColArray *dpobjca_ctl; /* dp column array handle for obj*/
OCIDirPathColArray *dpnestedobjca_ctl; /* dp col array hndl for nested obj*/
OCIDirPathStream *dpstr_ctl; /* direct path stream handle */
ub1 *buf_ctl; /* pre-alloc'd buffer for out-of-line data */
ub4 bufsz_ctl; /* size of buf_ctl in bytes */
ub4 bufoff_ctl; /* offset into buf_ctl */
ub4 *otor_ctl; /* Offset to Recnum mapping */
ub1 *inbuf_ctl; /* buffer for input records */
struct pctx pctx_ctl; /* partial field context */
boolean loadobjcol_ctl; /* load to obj col(s)? T/F */
};
demoディレクトリのヘッダー・ファイルcdemodp.hで、次の構造体を定義します。
#ifndef cdemodp_ORACLE
# define cdemodp_ORACLE
# include <oratypes.h>
# ifndef externdef
# define externdef
# endif
/* External column attributes */
struct col
{
text *name_col; /* column name */
ub2 id_col; /* column load id */
ub2 exttyp_col; /* external type */
text *datemask_col; /* datemask, if applicable */
ub1 prec_col; /* precision, if applicable */
sb1 scale_col; /* scale, if applicable */
ub2 csid_col; /* character set id */
ub1 date_col; /* is column a chrdate or date? 1=TRUE. 0=FALSE */
struct obj * obj_col; /* description of object, if applicable */
#define COL_OID 0x1 /* col is an OID */
ub4 flag_col;
};
/* Input field descriptor
* For this example (and simplicity),
* fields are strictly positional.
*/
struct fld
{
ub4 begpos_fld; /* 1-based beginning position */
ub4 endpos_fld; /* 1-based ending position */
ub4 maxlen_fld; /* max length for out of line field */
ub4 flag_fld;
#define FLD_INLINE 0x1
#define FLD_OUTOFLINE 0x2
#define FLD_STRIP_LEAD_BLANK 0x4
#define FLD_STRIP_TRAIL_BLANK 0x8
};
struct obj
{
text *name_obj; /* type name*/
ub2 ncol_obj; /* number of columns in col_obj*/
struct col *col_obj; /* column attributes*/
struct fld *fld_obj; /* field descriptor*/
ub4 rowoff_obj; /* current row offset in the column array*/
ub4 nrows_obj; /* number of rows in col array*/
OCIDirPathFuncCtx *ctx_obj; /* Function context for this obj column*/
OCIDirPathColArray *ca_obj; /* column array for this obj column*/
ub4 flag_obj; /* type of obj */
#define OBJ_OBJ 0x1 /* obj col */
#define OBJ_OPQ 0x2 /* opaque/sql str col */
#define OBJ_REF 0x4 /* ref col */
};
struct tbl
{
text *owner_tbl; /* table owner */
text *name_tbl; /* table name */
text *subname_tbl; /* subname, if applicable */
ub2 ncol_tbl; /* number of columns in col_tbl */
text *dfltdatemask_tbl; /* table level default date mask */
struct col *col_tbl; /* column attributes */
struct fld *fld_tbl; /* field descriptor */
ub1 parallel_tbl; /* parallel: 1 for true */
ub1 nolog_tbl; /* no logging: 1 for true */
ub4 xfrsz_tbl; /* transfer buffer size in bytes */
text *objconstr_tbl; /* obj constr/type if loading a derived obj */
};
struct sess /* options for a direct path load session */
{
text *username_sess; /* user */
text *password_sess; /* password */
text *inst_sess; /* remote instance name */
text *outfn_sess; /* output filename */
ub4 maxreclen_sess; /* max size of input record in bytes */
};
#endif /* cdemodp_ORACLE */
次のコードは、OCIダイレクト・パス・インタフェースの使用方法の例です。ただし、一部省略されています。
init_load関数は、tblpで記述された表上で、ダイレクト・パスAPIを使用してダイレクト・パス・ロードを実行します。ctlpによって指定されたloadctl構造体の環境およびサービス・コンテキストは、適切に初期化されています。サーバーへの接続は確立されています。
STATICF void
init_load(ctlp, tblp)
struct loadctl *ctlp;
struct tbl *tblp;
{
struct col *colp;
struct fld *fldp;
sword ociret; /* return code from OCI calls */
OCIDirPathCtx *dpctx; /* direct path context */
OCIParam *colDesc; /* column parameter descriptor */
ub1 parmtyp;
ub1 *timestamp = (ub1 *)0;
ub4 size;
ub4 i;
ub4 pos;
/* allocate and initialize a direct path context */
/* See cdemodp.c for the definition of OCI_CHECK */
OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp,
OCIHandleAlloc((void *)ctlp->envhp_ctl,
(void **)&ctlp->dpctx_ctl,
(ub4)OCI_HTYPE_DIRPATH_CTX,
(size_t)0, (void **)0));
dpctx = ctlp->dpctx_ctl; /* shorthand */
OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
OCIAttrSet((void *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX,
(void *)tblp->name_tbl,
(ub4)strlen((const char *)tblp->name_tbl),
(ub4)OCI_ATTR_NAME, ctlp->errhp_ctl));
OCI_ATTR_SUB_NAME、OCI_ATTR_SCHEMA_NAMEなど、その他の属性も設定します。属性を設定した後、ロードの準備をします。
OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
OCIDirPathPrepare(dpctx, ctlp->svchp_ctl, ctlp->errhp_ctl));
ダイレクト・パス・コンテキスト・ハンドルは、列配列ハンドルおよびストリーム・ハンドルの親ハンドルです。また、エラーは、ダイレクト・パス・コンテキストに関連付けられている環境ハンドルとともに戻されます。
OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp,
OCIHandleAlloc((void *)ctlp->dpctx_ctl, (void **)&ctlp->dpca_ctl,
(ub4)OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
(size_t)0, (void **)0));
OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp,
OCIHandleAlloc((void *)ctlp->dpctx_ctl,(void **)&ctlp->dpstr_ctl,
(ub4)OCI_HTYPE_DIRPATH_STREAM,
(size_t)0, (void **)0));
割り当てた列配列から行数および列数を取得します。
OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
OCIAttrGet(ctlp->dpca_ctl, (ub4)OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
&ctlp->nrow_ctl, 0, OCI_ATTR_NUM_ROWS,
ctlp->errhp_ctl));
OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
OCIAttrGet(ctlp->dpca_ctl, (ub4)OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
&ctlp->ncol_ctl, 0, OCI_ATTR_NUM_COLS,
ctlp->errhp_ctl));
入力データ・フィールドを対応するデータ列に設定します。
ub4 rowoff; /* column array row offset */
ub4 clen; /* column length */
ub1 cflg; /* column state flag */
ub1 *cval; /* column character value */
OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
OCIDirPathColArrayEntrySet(ctlp->dpca_ctl, ctlp->errhp_ctl,
rowoff, colp->id_col,
cval, clen, cflg));
前の変換を続ける必要がある場合、または行にデータを追加する場合は、列配列の状態をリセットします。
(void) OCIDirPathColArrayReset(ctlp->dpca_ctl, ctlp->errhp_ctl);
ストリームの状態をリセットして、新しいストリームを開始します。リセットしなかった場合は、ストリーム内のデータが既存のデータの末尾に追加されます。
(void) OCIDirPathStreamReset(ctlp->dpstr_ctl, ctlp->errhp_ctl);
データの入力後、列配列内のデータをストリーム形式に変換し、不正なレコードを削除します。
ub4 rowcnt; /* number of rows in column array */
ub4 startoff; /* starting row offset into column array */
/* convert array to stream, filter out bad records */
ocierr = OCIDirPathColArrayToStream(ctlp->dpca_ctl, ctlp->dpctx_ctl,
ctlp->dpstr_ctl, ctlp->errhp_ctl,
rowcnt, startoff);
ストリームを生成した列配列のオフセット情報とともに、ストリーム・ハンドルに対するストリーム内の位置は変わりません。ストリーム形式への変換が終わると、そのデータはストリームの末尾に追加されます。ストリームは、適切なタイミングでコール元がリセットする必要があります。エラーの発生時には、位置は次の行に移動します。ただし、最後の列でエラーが発生した場合は、ストリームの末尾に移動します。次の行がある場合は、次のOCIDirPathLoadStream()コールが開始されます。OCIDirPathLoadStream()がコールされ、ストリームの末尾に到達した場合は、OCI_NO_DATAが戻されます。
/* load the stream */
ociret = OCIDirPathLoadStream(ctlp->dpctx_ctl, ctlp->dpstr_ctl,
ctlp->errhp_ctl);
/* free up server data structures for the load */
OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
OCIDirPathFinish(ctlp->dpctx_ctl, ctlp->errhp_ctl));
割り当てられているすべてのダイレクト・パス・ハンドルを解放します。親のダイレクト・パス・コンテキスト・ハンドルの解放前に、ダイレクト・パス列配列ハンドルとストリーム・ハンドルが解放されます。
ociret = OCIHandleFree((void *)ctlp->dpca_ctl,
OCI_HTYPE_DIRPATH_COLUMN_ARRAY);
ociret = OCIHandleFree((void *)ctlp->dpstr_ctl,
OCI_HTYPE_DIRPATH_STREAM);
ociret = OCIHandleFree((void *)ctlp->dpctx_ctl,
OCI_HTYPE_DIRPATH_CTX);
表に格納するためにデータ型変換が必要なOracle日付およびタイムスタンプの値をロードする場合は、日付キャッシュ機能を使用するとパフォーマンスが向上します。
この機能は、同じ日付が入力値として繰返しロードされる場合に使用します。日付変換は(特に複数の日付列がロードされる場合)、非常に時間がかかり、ロード時間の中で大きな割合を占める場合があります。入力データに多数の同じ日付値がある場合は、この機能を使用すると実際に変換される日付の数が減少するため、パフォーマンスが向上します。ただし、日付キャッシュ機能によってパフォーマンスが向上するのは、多数の同じ日付が入力値として日付列にロードされる場合のみです(この章で使用する「日付」という用語は、日付およびタイムスタンプのすべてのデータ型を指します)。
日付キャッシュ・サイズを明示的に指定した場合、デフォルトでは日付キャッシュ機能は使用禁止になりません。この動作をオーバーライドするには、OCI_ATTR_DIRPATH_DCACHE_DISABLEを1に設定します。この設定以外の場合は、データ変換を回避するためにキャッシュが検索されます。ただし、キャッシュ・ミスが発生すると、変換のために時間がかかります。
OCI_ATTR_DIRPATH_DCACHE_NUM属性、OCI_ATTR_DIRPATH_DCACHE_MISSES属性およびOCI_ATTR_DIRPATH_DCACHE_HITS属性を問い合せて、ロードに必要なキャッシュ・サイズを調整します。
キャッシュ・ミスがなく、キャッシュ内の要素数がキャッシュ・サイズより小さい場合は、キャッシュ・サイズを小さくします。多数のキャッシュ・ミスが発生し、相対的にヒット数が少ない場合は、キャッシュ・サイズを大きくすることができます。キャッシュ・サイズを大きくしすぎると、ページングやメモリー消費量の増加など、別の問題が発生する可能性があります。キャッシュ・サイズを大きくしてもパフォーマンスが向上しない場合、この機能は使用しないでください。
日付キャッシュ機能を明示的かつ全体的に使用禁止にするには、日付キャッシュ・サイズを0(ゼロ)に設定します。
この機能では、次のOCIダイレクト・パス・コンテキスト属性を設定できます。
この属性を0(ゼロ)以外に設定する場合は、表に対する日付キャッシュ・サイズを要素数で設定します。たとえば、日付キャッシュ・サイズを200に設定すると、最大200個の一意の日付またはタイムスタンプ値をキャッシュに格納できます。OCIDirPathPrepare()をコールした後は、日付キャッシュ・サイズを変更できません。デフォルト値は0(ゼロ)で、これは表に対する日付キャッシュが作成されないことを意味します。日付キャッシュは、データ型変換が必要な1つ以上の日付またはタイムスタンプ値がロードされ、この属性値が0(ゼロ)以外の場合のみ、表に対して作成されます。
この属性を使用して、現在の日付キャッシュ・ミス数を問い合せます。この数が多い場合は、日付キャッシュ・サイズを大きくするようにアプリケーションを調整することを検討してください。日付キャッシュ・サイズを大きくしてもこの数が大幅に減少しない場合は、日付キャッシュ機能を使用しないでください。日付キャッシュ・ミスが発生すると、ハッシングや参照のために時間を費やします。
この属性を使用して、日付キャッシュ・ヒット数を問い合せます。日付キャッシュ機能の使用による効果があることを確認するには、この数が相対的に多くなる必要があります。
この属性を1に設定すると、サイズを超えた場合に日付キャッシュが使用禁止になります。OCIDirPathPrepare()をコールした後は、この属性を変更または設定できません。
デフォルト(= 0)では、オーバーフロー時にキャッシュが使用禁止になりません。キャッシュが使用禁止でない場合は、変換を回避するためにキャッシュが検索されますが、入力された日付値のエントリがオーバーフローすると日付キャッシュには追加されず、時間がかかる日付変換関数を使用して変換されます。多数の日付キャッシュ・ミスが発生すると、アプリケーションの処理速度は日付キャッシュを使用しない場合よりも遅くなる場合があります。
この属性を問い合せると、オーバーフローが原因で日付キャッシュが使用禁止になっているかどうかも確認できます。
この項では、ダイレクト・パス関数コンテキストによる多様な非スカラー型のロードについて説明します。
非スカラー型は、次のとおりです。
ネストした表
オブジェクト表(FINALとNOT FINAL)
列オブジェクト(FINALとNOT FINAL)
REF列(FINALとNOT FINAL)
SQL文字列の列
ネストした表は、別の表に格納されます。ダイレクト・パス・ロードAPIを使用して、ネストした表をSETIDという外部キーで、その親の表とは別にロードし、2つの表をリンクします。
|
注意:
|
ネストした表の列を持つ親表のロードと、子であるネストした表のロードは、別のアクションです。
ネストした表の列を持つ親表をロードする手順は、次のとおりです。
親表とその列を通常どおり記述しますが、このとき、次の手順を行います。
ネストした表の列を記述するときに、この列にSETIDを格納します。外部データ型は、データ・ファイルのSETIDが文字の場合はSQLT_CHRで、バイナリの場合はSQLT_BINです。
ネストした表(子)をロードする手順は、次のとおりです。
ネストした表とその列を通常どおり記述します。
SETID列は必須です。
ダミーの名前(setidなど)を使用して、そのOCI_ATTR_NAMEを設定します。これは、APIでは、プログラマがそのシステム名を認識しているとはみなしていないためです。
列がSETID列であることを示すには、次のように、OCI_ATTR_DIRPATH_SIDを使用して列属性を設定します。
ub1 flg = 1;
sword error;
error = OCIAttrSet((void *)colDesc,
OCI_DTYPE_PARAM,
(void *)&flg, (ub4)0,
OCI_ATTR_DIRPATH_SID, ctlp->errhp_ctl);
列オブジェクトとは、オブジェクトとして定義される表の列のことです。現在は、すべての構成属性で構成されるデフォルト・コンストラクタのみがサポートされています。
列オブジェクトとそのオブジェクト属性を記述するには、ダイレクト・パス関数コンテキストを使用します。列オブジェクトの記述には、そのオブジェクトのコンストラクタの設定が必要です。オブジェクト属性の記述は、スカラー列のリストの記述に類似しています。
列オブジェクトを記述する手順は、次のとおりです。
|
注意:
|
1. パラメータ・ハンドルをOCI_DTYPE_PARAMで列オブジェクトに割り当てます。このパラメータ・ハンドルを使用して、列の外部属性を設定します。
2. 列名とその他の外部列の属性(最大データ・サイズ、精度、スケールなど)を設定します。
3. OCI_ATTR_DATA_TYPEで、外部型をSQLT_NTY(名前付き型)として設定します。
4. ダイレクト・パス関数コンテキスト・ハンドルを割り当てます。このコンテキストを使用して、列のオブジェクト型と属性を記述します。
OCIDirPathFuncCtx *dpfnctx /* direct path function context */;
sword error;
error = OCIHandleAlloc((void *)dpctx, (void **)&dpfnctx,
OCI_HTYPE_DIRPATH_FN_CTX,
(size_t)0, (void **)0);
5. 関数コンテキストのOCI_ATTR_NAMEで列のオブジェクト型の名前(Employeeなど)を設定します。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
text *obj_type; /* column object's object type */
sword error;
error = OCIAttrSet((void *)dpfnctx,
OCI_HTYPE_DIRPATH_FN_CTX,
(void *)obj_type, (ub4)strlen((const char *)obj_type),
OCI_ATTR_NAME, ctlp->errhp_ctl);
6. 式の型OCI_ATTR_DIRPATH_EXPR_TYPEをOCI_DIRPATH_EXPR_OBJ_CONSTRに設定します。これは、OCI_ATTR_NAMEを持つ式セットが、デフォルトのオブジェクト・コンストラクタとして使用されることを意味します。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
ub1 expr_type = OCI_DIRPATH_EXPR_OBJ_CONSTR;
sword error;
error = OCIAttrSet((void *)dpfnctx,
OCI_HTYPE_DIRPATH_FN_CTX,
(void *)&expr_type, (ub4)0,
OCI_ATTR_DIRPATH_EXPR_TYPE,
ctlp->errhp_ctl);
7. OCI_ATTR_NUM_COLSを使用して、この列オブジェクトにロードする列またはオブジェクト属性の数を設定します。
8. 関数コンテキストOCIDirPathFuncCtxの列/属性のパラメータ・リストを取得します。
9. 各オブジェクト属性の場合:
OCI_DTYPE_PARAMで、オブジェクト属性の列記述子を取得します。
OCI_ATTR_NAMEで属性の列名を設定します。
OCI_ATTR_DATA_TYPEで外部列の型(ダイレクト・パスAPIに渡されるデータの型)を設定します。
その他の外部列の属性(最大データ・サイズ、精度、スケールなど)を設定します。
この属性の列が列オブジェクトの場合は、そのオブジェクト属性に対して手順3〜10を実行します。
列記述子へのハンドルを解放します。
10. 手順4で作成した関数コンテキストOCIDirPathFuncCtxを、親の列オブジェクトのパラメータ・ハンドルにOCI_ATTR_DIRPATH_FN_CTXを使用して設定します。
列オブジェクトをロードすると、そのオブジェクトの属性データは、そのオブジェクト専用に作成された個別の列配列にロードされます。子の列配列は、ネストされているかどうかに関係なく、各列オブジェクトに割り当てられます。子の列配列にあるオブジェクト属性の各行は、その親列配列内の親の列オブジェクトにある対応するNULL以外の行にマップされて戻されます。
列オブジェクトのダイレクト・パス関数コンテキスト・ハンドルとOCI_HTYPE_DIRPATH_FN_COL_ARRAY列配列型を使用します。
列オブジェクトに子の列配列を割り当てるには、次のように行います。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
OCIDirPathColArray *dpfnca; /* direct path function column array */
sword error;
error = OCIHandleAlloc((void *)dpfnctx, (void **)&dpfnca,
OCI_HTYPE_DIRPATH_FN_COL_ARRAY,
(size_t)0, (void **)0);
列がスカラー列の場合は、その値のアドレスをOCIDirPathColArrayEntrySet()に渡して、その値を列配列に設定します。列がオブジェクトの場合は、かわりに、子の列配列ハンドルのアドレスを渡します。子の列配列にはオブジェクトの属性データが格納されます。
データを列オブジェクトにロードする手順は、次のとおりです。
(開始)列オブジェクトごとに、次の操作を行います。
列がNULL以外の場合:
オブジェクト属性の列ごとに、次の操作を行います。
オブジェクト属性がネストされた列オブジェクトの場合は、(開始)に移動し、この全手順を繰り返し実行します。
OCIDirPathColArrayEntrySet()を使用して、子の列配列にデータを設定します。
列オブジェクトのデータを列配列に設定するには、子の列配列ハンドルのアドレスをOCIDirPathColArrayEntrySet()に渡します。
列がNULLの場合:
データのNULLアドレス、長さ0(ゼロ)およびOCI_DIRPATH_COL_NULLフラグをOCIDirPathColArrayEntrySet()に渡して、列オブジェクトのデータを列配列に設定します。
この値をOCIDirPathColArrayEntry()に渡すことにより、現在の列配列行を無視する必要があることを示します。一部の列にデータを追加するときにエラーが発生した場合(前のOCIDirPathColArrayToStream()コールからOCI_NEED_DATAが戻された場合)は、通常、この値を使用して前のすべての行変換を取り消します。現在の行の出力ストリーム・バッファに格納されている、前に変換されたデータは削除されます。これにより、変換は列配列内の次の行から続行されます。削除された行は、変換された行としてカウントされます。
OCI_DIRPATH_COL_ERRORを指定すると、現在の行の他、参照される子列配列で対応する任意の行(最上位レベルの列配列行までの行)が無視されます。参照されるすべての子列配列を次の行に移動すると、NULL子列配列参照は無視されます。
列の値は、SQL文字列で計算できます。SQL文字列は、スカラー列の型に使用できます。SQL文字列は、オブジェクト型には使用できませんが、スカラー列の型のオブジェクト属性には使用できます。 NESTED TABLE、SEQUENCEおよびLONGには使用できません。
SQL式は、OCIDirPathFuncCtxを使用してダイレクト・パスAPIで表現します。式のOCI_ATTR_NAMEの値が、その式の名前付きバインド変数のパラメータ・リストを含むSQL文字列になります。
バインド変数のネームスペースは、列のSQL文字列に限定されています。複数の列に対して同じバインド変数名を使用できますが、同じ名前の引数はその列のSQL文字列に対してのみ適用されます。
バインド変数に対する参照が列のSQL文字列に複数含まれており、その名前に複数の引数が指定されている場合、すべての値が同じである必要があります。同じでない場合、結果は未定義になります。この場合、特定のSQL式内の同じバインド変数名に対するすべての参照が単一の引数に対してバインドされるため、実際には1つの引数のみが必要になります。
SQL文字列の例を、次に示します。
substr(substr(:string, :offset, :length), :offset, :length)
この例では、次の点に注意してください。
SQL式はネストできます。
バインド変数名は、その式内で繰り返し指定できます。
パラメータ・ハンドルをOCI_DTYPE_PARAMでSQL文字列の列に割り当てます。このパラメータ・ハンドルを使用して、列の外部属性を設定します。
列名とその他の外部列の属性(最大データ・サイズ、精度、スケールなど)を設定します。
OCI_ATTR_DATA_TYPEを使用して、SQL文字列の列の外部型をSQLT_NTYとして設定します。
ダイレクト・パス関数コンテキスト・ハンドルを割り当てます。このコンテキストを使用して、SQL文字列の引数を記述します。
OCIDirPathFuncCtx *dpfnctx /* direct path function context */;
sword error;
error = OCIHandleAlloc((void *)dpctx, (void **)&dpfnctx,
OCI_HTYPE_DIRPATH_FN_CTX,
(size_t)0, (void **)0);
列のSQL文字列を関数コンテキストのOCI_ATTR_NAMEに設定します。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
text *sql_str; /* column's SQL string expression */
sword error;
error = OCIAttrSet((void *)dpfnctx,
OCI_HTYPE_DIRPATH_FN_CTX,
(void *)sql_str, (ub4)strlen((const char *)sql_str),
OCI_ATTR_NAME, ctlp->errhp_ctl);
式の型OCI_ATTR_DIRPATH_EXPR_TYPEをOCI_DIRPATH_EXPR_SQLとして設定します。これは、OCI_ATTR_NAMEを持つ式セットが、値を導出するためのSQL文字列として使用されることを意味します。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
ub1 expr_type = OCI_DIRPATH_EXPR_SQL;
sword error;
error = OCIAttrSet((void *)dpfnctx,
OCI_HTYPE_DIRPATH_FN_CTX,
(void *)&expr_type, (ub4)0,
OCI_ATTR_DIRPATH_EXPR_TYPE, ctlp->errhp_ctl);
SQL文字列に渡す引数の数をOCI_ATTR_NUM_COLSを使用して設定します。
関数コンテキストの列/属性のパラメータ・リストを取得します。
SQL文字列の引数ごとに、次の操作を行います。
OCI_DTYPE_PARAMで、オブジェクト属性の列記述子を取得します。
SQL文字列の引数の定義順序は重要ではありません。SQL文字列で使用されている順序と一致させる必要はありません。
OCI_ATTR_NAMEで属性の列名を設定します。
SQL文字列の引数には、次のネーミング規則が適用されます。
引数名は、SQL文字列で使用されているバインド変数名と内容が一致している必要がありますが、大/小文字区別を一致させる必要はありません。たとえば、SQL文字列がsubstr(:INPUT_STRING, 3, 5)の場合は、引数名をinput_stringにしてもかまいません。
1つの引数をSQL文字列内で繰り返し使用する場合は、宣言は1回のみ実施し、1つの引数としてのみカウントしてください。
OCI_ATTR_DATA_TYPEで外部列の型(ダイレクト・パスAPIに渡されるデータの型)を設定します。
その他の外部列の属性(最大データ・サイズ、精度、スケールなど)を設定します。
列記述子へのハンドルを解放します。
手順4で作成した関数コンテキストOCIDirPathFuncCtxを、親の列オブジェクトのパラメータ・ハンドルにOCI_ATTR_DIRPATH_FN_CTXを使用して設定します。
SQL文字列の列をロードすると、その引数のデータは、そのSQL文字列の列専用に作成された個別の列配列にロードされます。子の列配列は、SQL文字列の列ごとに割り当てられます。子の列配列にある引数の各行は、その親列配列内の親のSQL文字列の列にある対応するNULL以外の行にマップされて戻されます。
SQL文字列の列に子の列配列を割り当てるには、次のようにします。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
OCIDirPathColArray *dpfnca; /* direct path function column array */
sword error;
error = OCIHandleAlloc((void *)dpfnctx, (void **)&dpfnca,
OCI_HTYPE_DIRPATH_FN_COL_ARRAY,
(size_t)0, (void **)0);
列がスカラー列の場合は、その値のアドレスをOCIDirPathColArrayEntrySet()に渡して、その値を列配列に設定します。列がSQL文字列型の場合は、かわりに、子の列配列ハンドルのアドレスを渡します。子の列配列には、SQL文字列の引数データが格納されます。
データをSQL文字列の列にロードする手順は、次のとおりです。
SQL文字列の列ごとに、次の操作を行います。
列がNULL以外の場合:
関数の引数の列ごとに、次の操作を行います。
OCIDirPathColArrayEntrySet()を使用して、子の列配列にデータを設定します。
SQL文字列の列のデータを列配列に設定するには、その子の列配列ハンドルのアドレスをOCIDirPathColArrayEntrySet()に渡します。
列がNULLの場合:
データのNULLアドレス、長さ0(ゼロ)およびOCI_DIRPATH_COL_NULLフラグをOCIDirPathColArrayEntrySet()に渡して、SQL文字列の列データを列配列に設定します。
この処理は、列オブジェクトの処理に類似しています。
REF型とは、オブジェクト表の行オブジェクトへのポインタ、つまり参照です。
REF列への引数の記述は、表にロードする列リストの記述に類似しています。
|
注意: REF列は、表のトップレベル列に設定したり、オブジェクト属性として列オブジェクトにネストできます。 |
OCI_DTYPE_PARAMで、REF列のパラメータ・ハンドルを取得します。このパラメータ・ハンドルを使用して、列の外部属性を設定します。
列名とその他の外部列の属性(最大データ・サイズ、精度、スケールなど)を設定します。
OCI_ATTR_DATA_TYPEを使用して、REF列の外部型をSQLT_REFとして設定します。
ダイレクト・パス関数コンテキスト・ハンドルを割り当てます。このコンテキストを使用して、REF列の引数を記述します。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
sword error;
error = OCIHandleAlloc((void *)dpctx, (void **)&dpfnctx,
OCI_HTYPE_DIRPATH_FN_CTX,
(size_t)0, (void **)0);
オプション: REF列の表名を関数コンテキストのOCI_ATTR_NAMEに設定します。詳細は、次の手順を参照してください。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
text *ref_tbl; /* column's reference table */
sword error;
error = OCIAttrSet((void *)dpfnctx,
OCI_HTYPE_DIRPATH_FN_CTX,
(void *)ref_tbl, (ub4)strlen((const char *)ref_tbl),
OCI_ATTR_NAME, ctlp->errhp_ctl);
オプション: 式の型OCI_ATTR_DIRPATH_EXPR_TYPEをOCI_DIRPATH_EXPR_REF_TBLNAMEに設定します。この設定は、手順5が完了している場合にのみ実行します。これは、OCI_ATTR_NAMEを持つ式セットが、行オブジェクトを参照するためのオブジェクト表として使用されることを意味します。このパラメータは、オプションです。このパラメータの動作は、REFの型によって異なります。
有効範囲なしのREF列(有効範囲なし、システムOIDベース)
このパラメータが設定されていない場合、このREF列には、有効範囲なしのREF列の定義により、参照表の名前が引数としてデータ行ごとに含まれている必要があります。
パラメータが設定されている場合、このREF列がロードの継続時間中に参照できるのは、指定されたオブジェクト表の行オブジェクトのみです。このREF列に、参照表の名前を引数として含めることはできません(ダイレクト・パスAPIは、このパラメータをショート・カットとしてユーザーに提供しています。ユーザーは、このパラメータをロードの継続時間中に同じ参照オブジェクト表を参照する有効範囲なしのREF列にロードします)。
有効範囲付REF列(有効範囲付、システムOIDベースおよび主キー・ベース)
このパラメータが設定されていない場合、ダイレクト・パスAPIは、スキーマで指定されている参照表を使用します。
このパラメータが設定されている場合、参照表の名前は、この有効範囲付REF列のスキーマに指定されているオブジェクト表と一致している必要があります。表名が一致していない場合は、エラーが発生します。
このパラメータが設定されているかどうかに関係なく、この参照表の名前がデータ行に存在しているかどうかはAPIにとって問題ではありません。名前がデータ行にある場合、その名前はスキーマに指定されている表名と一致している必要があります。名前がデータ行にない場合、APIはスキーマに指定されている参照表を使用します。
行オブジェクトの参照に使用するREF引数の数を、OCI_ATTR_NUM_COLSで設定します。必要な引数の数は、REF列の型によって異なります。この数は、前述の手順6で導出されます。
有効範囲なしのREF列(有効範囲なし、システムOIDベースのREF列)
OCI_DIRPATH_EXPR_REF_TBLNAMEが使用されている場合は、1つの引数が導出されます。参照表の名前の引数はなく、OID値の引数が1つです。
OCI_DIRPATH_EXPR_REF_TBLNAMEが使用されていない場合は、2つの引数が導出されます。参照表の名前の引数が1つとOID値の引数が1つです。
有効範囲付REF列(有効範囲付、システムOIDベースおよび主キー・ベース)
OCI_DIRPATH_EXPR_REF_TBLNAMEを使用しているかどうかにかかわらず、オブジェクトIDを構成している列数がNの場合、受入れ可能な数はNまたはN+1です。参照表の名前がデータ行にない場合、最小値はNです。参照表の名前がデータ行にある場合、その最小値はN+1です。注意: REFがシステムOIDベースの場合、Nは1になります。REFが主キー・ベースの場合、Nは主キーを構成するコンポーネント列の数になります。参照表の名前がデータ行にある場合は、Nに1を加算します。
|
注意: エラー・メッセージを簡素化するために、NまたはN+1以外の数のREF引数を渡すと、期待値Nとは異なる数の引数が検出されたというエラー・メッセージが戻され、検出された引数の数が表示されます。メッセージではN+1について言及されていませんが、N+1は受入れ可能です(参照表の名前が不要な場合でも同様です)。したがって、エラー・メッセージは表示されません。 |
関数コンテキストの列/属性のパラメータ・リストを取得します。
REFの引数または属性ごとに、次の操作を行います。
OCI_DTYPE_PARAMで、REF引数の列記述子を取得します。
OCI_ATTR_NAMEで属性の列名を設定します。
REF引数の順序は重要です。参照表の名前が指定されている場合は、その名前を最初のREF引数に指定します。オブジェクトIDは、システム生成または主キー・ベースに関係なく、次のREF引数に指定します。
REF引数には次のネーミング規則が適用されます。参照表の名前は表の列ではないため、列名にref-tblなどのダミーの名前を使用できます。システム生成のOID列に対しては、列名にsys-OIDなどのダミーの名前を使用できます。主キー・ベースのオブジェクトIDに対しては、ロード対象のすべての主キー列をリストします。OIDに対してダミーの名前を作成する必要はありません。コンポーネント列名は、指定されている場合(次のショート・カットの注意を参照)、任意の順序で指定できます。
ショート・カットを使用する場合は、オブジェクトIDに属性列名を設定しないでください。
ショート・カット − システムOIDベースのREF列をロードする場合は、列名に名前を設定しないでください。名前はAPIによって判断されます。ただし、外部データ型などの他の列属性は、プログラマが設定する必要があります。
主キーREF列をロードしており、その主キーが複数の列で構成されている場合、ショート・カットはそれぞれの列名に設定されません。ただし、外部データ型などの他の列属性は、プログラマが設定する必要があります。
|
注意: コンポーネント列名がNULLの場合は、APIコードによって、主キーに定義された位置または順序で列名が決定されます。したがって、名前以外の列属性を設定する場合は、その属性がコンポーネントの列に適切な順序で設定されていることを確認してください。 |
OCI_ATTR_DATA_TYPEで外部列の型(ダイレクト・パスAPIに渡されるデータの型)を設定します。
その他の外部列の属性(最大データ・サイズ、精度、スケールなど)を設定します。
列記述子へのハンドルを解放します。
手順4で作成された関数コンテキストOCIDirPathFuncCtxを、OCI_ATTR_DIRPATH_FN_CTXを使用して親の列オブジェクトのパラメータ・ハンドルに設定します。
REF列に子の列配列を割り当てるには、次のようにします。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
OCIDirPathColArray *dpfnca; /* direct path function column array */
sword error;
error = OCIHandleAlloc((void *)dpfnctx, (void **)&dpfnca,
OCI_HTYPE_DIRPATH_FN_COL_ARRAY,
(size_t)0, (void **)0);
列がスカラー列の場合は、その値のアドレスをOCIDirPathColArrayEntrySet()に渡して、その値を列配列に設定します。列がREFの場合は、かわりに、子の列配列ハンドルのアドレスを渡します。子の列配列には、REFの引数のデータが格納されます。
データをREF列にロードする手順は、次のとおりです。
REF列ごとに、次の操作を行います。
列がNULL以外の場合:
REF引数の列ごとに、次の操作を行います。
OCIDirPathColArrayEntrySet()を使用して、子の列配列にデータを設定します。
REF列のデータを列配列に設定するには、子の列配列ハンドルのアドレスをOCIDirPathColArrayEntrySet()に渡します。
列がNULLの場合:
データのNULLアドレス、長さ0(ゼロ)およびOCI_DIRPATH_COL_NULLフラグをOCIDirPathColArrayEntrySet()に渡して、REF列のデータを列配列に設定します。
継承の階層の例を次の項に示します。
この例のPersonは、階層の最上位にあります。その下には、EmployeeとStudentという2つのサブタイプがあります。ParttimeEmployeeはEmployeeのサブタイプです。したがって、Personの列に格納できる型は、次の図のとおりです。
Person (Name, Address)
| |
| |
Student(Units, GPA) Employee (Manager, Deptid)
|
|
ParttimeEmployee (Hours)
Person型の列を含む表をロードする場合、実際の型セットには、NOT FINAL型Personとその3つのサブタイプであるStudent、EmployeeおよびParttimeEmployeeを含めることができます。このロードの継続時間中、ダイレクト・パスAPIがサポートするのは、このNOT FINAL列の固定的な派生型のロードのみです。したがって、APIでは、ロード対象となる型、その型の属性およびその型の作成に使用する関数などを認識する必要があります。
|
注意:
|
NOT FINALまたは置換可能オブジェクトと固定的な派生型のREF列を記述する手順は、次のとおりです。
|
注意: 固定的な派生型の NOT FINAL列を記述するステップは、同じ型のFINAL列を記述するステップと類似しています。 |
X型(XはオブジェクトまたはREF)のNOT FINAL列を記述するには、この型のFINAL列を記述している前述の各項を参照してください。派生型(スーパータイプまたはサブタイプの場合があります)は、ロードの継続時間中固定されているため、NOT FINAL列を記述するためのクライアント側インタフェースは、FINAL列の場合と同じです。
サブタイプは、この型とその親の全属性に固有なすべてのオブジェクト属性のフラット表現とみなすことができます。したがって、ロード対象の属性列すべてを記述してカウントする必要があります。
オブジェクト表とは、すべての行がオブジェクト(つまり、行オブジェクト)である表です。表の各列は、オブジェクト属性です。
オブジェクト表の記述は、非オブジェクト表の記述と非常に類似しています。各オブジェクト属性が表の列です。唯一の相違点は、OIDがシステム生成、ユーザー生成または主キー・ベースの場合に、そのOIDの記述が必要になることです。
オブジェクト表を記述する手順は、次のとおりです。
オブジェクト属性列ごとに、次の操作を行います。
それぞれの型(NUMBER、REFなど)に基づいて、各オブジェクト属性の列を必要に応じて記述します。
オブジェクト表がOID(Oracle Internet Directory)の場合は、次の操作を行います。
オブジェクトIDがシステム生成の場合。
何もする必要はありません。システムがすべての行オブジェクトのOIDを生成します。
オブジェクトIDがユーザー生成の場合。
仮の名前(cust_oidなど)を使用してOIDの列名を表現します。
OCI_ATTR_DIRPATH_OIDでOIDの列属性を設定します。
オブジェクトIDが主キー・ベースの場合。
OIDを構成しているすべての主キー列のロードが必要です。
OCI_ATTR_DIRPATH_OIDを設定しないでください。ダミーの名前を持つOID列は作成されていません。
NOT FINALオブジェクト表は継承をサポートしますが、FINALオブジェクト表は継承をサポートできません。
固定的な派生型のNOT FINALオブジェクト表の記述は、FINALオブジェクト表の記述と非常に類似しています。
固定的な派生型のNOT FINALオブジェクト表を記述する手順は、次のとおりです。
OCI_ATTR_DIRPATH_OBJ_CONSTRを使用して、ダイレクト・パス・コンテキストにオブジェクト表のオブジェクト型を設定します。これは、スーパータイプまたは派生型に関係なく、ロードの継続時間中、この表へのロードにはオブジェクト型がデフォルトのオブジェクト・コンストラクタとして使用されることを意味します。
text *obj_type; /* the object type to load into this NOT FINAL */
/* object table */
sword error;
error = OCIAttrSet((void *)dpctx,
OCI_HTYPE_DIRPATH_CTX,
(void *) obj_type,
(ub4)strlen((const char *) obj_type),
OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl);
ロード対象のオブジェクト属性の列に、それぞれのデータ型に従って記述します。必要に応じて、オブジェクトIDを記述します。これは、FINALオブジェクト表を記述する方法と同じです。
一度にメモリー内に格納できないデータのロードをサポートするために、ピース単位のロードを使用します。
ダイレクト・パスAPIでは、すでにLONGとLOBの段階的なロードがサポートされています。これには、次の一連の手順を順に実行します。
最初のピースをOCIDirPathColArrayEntrySet()を使用して列配列に設定し、OCI_DIRPATH_COL_PARTIALフラグに渡して、この列の全データのロードが完了していないことを示します。
列配列をストリームに変換します。
ストリームをロードします。
そのデータの次のピースを列配列に設定します。このピースが未完了の場合は、パーシャル・フラグを設定して手順2に戻ります。完了している場合は、OCI_DIRPATH_COL_COMPLETEフラグを設定して次の列へ続行します。
このアプローチは、本質的には列オブジェクトの大規模な属性やSQL文字列型の大規模な引数を扱う方法と同じです。
|
注意: コレクションは、このようにピース単位でロードしません。NESTED TABLEは、トップレベル表と同じように、個別にロードします。NESTED TABLEは段階的にロードでき、またピース単位でロードされた列を含めることができます。したがって、コレクションを格納している列には、 OCI_DIRPATH_COL_PARTIALフラグを設定しないでください。 |
オブジェクトは、そのオブジェクトが格納されている親の表から個別の列配列にロードします。したがって、オブジェクトをピース単位でロードする必要がある場合は、子の列配列に要素を設定して、ピース化された要素を含める必要があります。
通常の手順は、次のとおりです。
ピース化された要素に、OCI_DIRPATH_COL_PARTIALフラグを設定します。
子の列配列ハンドルを親の列配列に設定し、そのエントリもOCI_DIRPATH_COL_PARTIALフラグでマークします。
この時点で、親の列配列をストリームに変換します。この結果、子の列配列もストリームに変換されます。
次に、ストリームをロードします。
手順1に戻り、その要素に対する残りのデータのロードを、完了するまで続行します。
ピース単位のロードには、いくつかのルールがあります。
パーシャル要素は、任意のレベルで一度に1つしか存在できません。1つのパーシャル要素が完了とマークされた後は、そのレベルの別の要素をパーシャル要素に設定できます。
要素がパーシャルで、かつトップレベルでない場合は、制御階層上のその要素のすべての親にもパーシャルのマークを付ける必要があります。
ネスト・レベルが複数の場合は、対象データをストリームに変換できるレベルまで移動する必要があります。これがトップレベル表になります。
次の説明では、付録Aにリストされているハンドルと属性の詳細を補足します。
1つ存在します。
オブジェクト型がNOT FINALオブジェクト表にロードされることを示します。
ttext *obj_type; /* the object type to load into this NOT FINAL */
/* object table */
sword error;
error = OCIAttrSet((void *)dpctx,
OCI_HTYPE_DIRPATH_CTX,
(void *) obj_type,
(ub4)strlen((const char *) obj_type),
OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl);
関数コンテキスト・ハンドルの属性の概要を、次に示します。
オブジェクト型が置換可能なオブジェクト表にロードされることを示します。
text *obj_type; /* stores an object type name */
sword error;
error = OCIAttrSet((void *)dpctx,
OCI_HTYPE_DIRPATH_CTX,
(void *) obj_type,
(ub4)strlen((const char *) obj_type),
OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl);
関数コンテキストの作成時に、非スカラー列を記述する式に相当するOCI_ATTR_NAMEを設定します。次に、式の型を示すOCI属性を設定します。次のように、様々な式の型があります。
列オブジェクト
REF列
このオプションの式は、参照表名です。この表は、REF列が行オブジェクトを参照する参照元のオブジェクト表です。
式の型OCI_ATTR_DIRPATH_EXPR_TYPEをOCI_DIRPATH_EXPR_REF_TBLNAMEに設定し、この式が参照オブジェクト表であることを示します。
このパラメータの動作は、設定の有無に関係なく、REFの型によって異なります。
有効範囲なしのREF列(有効範囲なし、システムOIDベース)
このパラメータが設定されていない場合、このREF列には、有効範囲なしのREF列の定義により、参照表の名前が引数としてデータ行ごとに含まれている必要があります。
パラメータが設定されている場合、このREF列がロードの継続時間中に参照できるのは、指定されたオブジェクト表の行オブジェクトのみです。このREF列に、参照表の名前を引数として含めることはできません(ダイレクト・パスAPIは、このパラメータをショート・カットとしてユーザーに提供しています。ユーザーは、このパラメータをロードの継続時間中に同じ参照オブジェクト表を参照する有効範囲なしのREF列にロードします)。
有効範囲付REF列(有効範囲付、システムOIDベースおよび主キー・ベース)
このパラメータが設定されていない場合、ダイレクト・パスAPIは、スキーマで指定されている参照表を使用します。
このパラメータが設定されている場合、参照表の名前は、この有効範囲付REF列のスキーマに指定されているオブジェクト表と一致している必要があります。表名が一致していない場合は、エラーが発生します。
このパラメータが設定されているかどうかに関係なく、この参照表の名前がデータ行に存在しているかどうかはAPIにとって問題ではありません。名前がデータ行にある場合、その名前はスキーマに指定されている表名と一致している必要があります。名前がデータ行にない場合、APIはスキーマに定義されている参照表を使用します。
SQL文字列の列
この必須式には、列に格納される値を導出するSQL文字列が含まれています。
式の型OCI_ATTR_DIRPATH_EXPR_TYPEをOCI_DIRPATH_EXPR_SQLに設定し、この式がSQL文字列であることを示します。
この属性を使用して、非スカラー列の関数コンテキストに対して、OCI_ATTR_NAMEで指定した式の型を示します。
OCI_ATTR_NAMEが設定されている場合、OCI_ATTR_DIRPATH_EXPR_TYPEは必須です。
OCI_ATTR_DIRPATH_EXPR_TYPEに使用可能な値は、次のとおりです。
式がオブジェクト型名であること、この式が列オブジェクトに対するデフォルトのオブジェクト・コンストラクタとして使用されることを示します。
列オブジェクトには必須です。
式が参照オブジェクト表の名前であることを示します。この表は、REF列が行オブジェクトを参照する参照元のオブジェクト表です。
REF列の場合は、オプションです。
式がSQL文字列であること、このSQL文字列が列に格納されている値を導出するために実行されることを示します。
SQL文字列の列の場合は、必須です。
次の疑似コードは、前述のルールを例示したものです。
OCIDirPathFuncCtx *dpfnctx; /* function context for this non-scalar column */
ub1 expr_type; /* expression type */
sword error;
if (...) /* (column type is an object) */
expr_type = OCI_DIRPATH_EXPR_OBJ_CONSTR;
...
if (...) /* (column_type is a REF && function context name exists) */
expr_type = OCI_DIRPATH_EXPR_REF_TBLNAME;
...
if (...) /* (column_type is a SQL string) */
expr_type = OCI_DIRPATH_EXPR_SQL;
...
error = OCIAttrSet((void *)(dpfnctx),
OCI_HTYPE_DIRPATH_FN_CTX,
(void *)&expr_type, (ub4)0,
OCI_ATTR_DIRPATH_EXPR_TYPE, ctlp->errhp_ctl);
この属性は、非スカラー列用にロードまたは処理する属性や引数の数を記述します。このパラメータは、列リストが取り出される前に設定する必要があります。
列オブジェクト
この列オブジェクト用にロードするオブジェクト属性列の数。
SQL文字列の列
SQL文字列に渡す引数の数。
引数が関数内で繰り返して使用される場合も、1つとしてカウントしてください。
REF列
REF列が指し示す必要のある行オブジェクトを識別するREF引数の数。
必要な引数の数は、REF列の型によって異なります。
有効範囲なしのREF列(有効範囲なし、システムOIDベースのREF列)
OCI_DIRPATH_EXPR_REF_TBLNAMEを使用している場合。参照表の名前の引数はなく、OID値の引数が1つです。(OID値のみがデータ行にある。)
OCI_DIRPATH_EXPR_REF_TBLNAMEを使用していない場合。参照表の名前の引数が1つとOID値の引数が1つです。(参照表名とOID値の両方がデータ行にある。)
有効範囲付REF列(有効範囲付、システムOIDベースおよび主キー・ベース)
OCI_DIRPATH_EXPR_REF_TBLNAMEを使用しているかどうかにかかわらず、オブジェクトIDを構成している列数がNの場合、受入れ可能な数はNまたはN+1です。参照表の名前がデータ行にない場合、最小値はNです。参照表の名前がデータ行にある場合は、N+1を使用します。
REFがシステムOIDベースの場合、Nは1になります。REFが主キー・ベースの場合、Nは主キーを構成するコンポーネント列の数になります。参照表の名前がデータ行にある場合は、Nに1を加算します。
|
注意: エラー・メッセージを簡素化するために、NまたはN+1以外の数のREF引数を渡すと、期待値Nとは異なる数の引数が検出されたというエラー・メッセージが戻され、検出された引数の数が表示されます。メッセージではN+1について言及されていませんが、N+1は受入れ可能です(参照表の名前が不要な場合でも同様です)。したがって、エラー・メッセージは表示されません。 |
OCI_HTYPE_DIRPATH_FN_CTX(関数コンテキスト)に対して使用される場合、この属性は、取出し専用のため、ユーザーによる設定はできません。この属性は、OCIAttrGet()にのみ使用でき、OCIAttrSet()には使用できません。OCIAttrGet()を使用してコールすると、それまでにロードされた行数が戻されます。
ただし、属性OCI_ATTR_NUM_ROWSは、OCI_HTYPE_DIRPATH_CTX(表レベルのコンテキスト)に対して使用する場合は設定可能で、ユーザーによる取出しが可能です。
OCIAttrSet()をOCI_ATTR_NUM_ROWSとOCI_HTYPE_DIRPATH_CTXを使用してコールすると、表レベルの列配列に割り当てる行数が設定されます。設定されない場合、ダイレクト・パスAPIコードは、レコード最大サイズと転送バッファのサイズに基づいて適切な数を導出します。割り当てた行数を確認するには、表レベルの列配列については、OCI_ATTR_NUM_ROWSをOCI_HTYPE_DIRPATH_COLUMN_ARRAYで使用し、関数列配列については、OCI_HTYPE_DIRPATH_FN_COL_ARRAYを使用してOCIAttrGet()をコールします。
OCIAttrGet()をOCI_ATTR_NUM_ROWSとOCI_HTYPE_DIRPATH_CTXでコールすると、それまでにロードされた行数が戻されます。
この属性は、ユーザーが関数コンテキストに設定することはできません。プログラマがOCIAttrSet()でOCI_ATTR_NUM_ROWSをコールして関数列配列に必要な行数を指定することは許可されていません。これは、コールすると、すべての関数列配列が表レベルの列配列と同じ行数を所有することになるためです。この属性を設定できるのは、表レベルのコンテキストのみで、関数コンテキストには設定できません。
オブジェクト、SQL文字列またはREF列を記述すると、その列属性の1つが関数コンテキストになります。
列がオブジェクトの場合、その関数コンテキストには、そのオブジェクト型とオブジェクト属性が記述されます。SQL文字列の場合は、コール対象の式が記述されます。REFの場合は、その参照表の名前と行オブジェクトの識別子が記述されます。
関数コンテキストを列属性として設定すると、OCIAttrSet()ではOCI_ATTR_DIRPATH_FN_CTXが使用されます。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
sword error;
error = OCIAttrSet((void *)colDesc,
OCI_DTYPE_PARAM,
(void *)(dpfnctx), (ub4)0,
OCI_ATTR_DIRPATH_FN_CTX, ctlp->errhp_ctl);
列パラメータ・コンテキスト・ハンドルの属性について次に説明します。
次に、ネストした表、オブジェクト表、SQL文字列の列およびREF列をロードするときのネーミング規則について説明します。
通常、オブジェクト表のシステム生成オブジェクトID(OID)列やネストした表のSETID(SID)列など、プログラマにとって不明なシステム名を持つシステム列にデータをロードする場合、あるいは列がデータベース表の列を持たない引数(SQL文字列やREF引数など)である場合は、ダミーの名前を使用します。
列はデータベース表の列であっても、ダミーの名前を使用した場合は、その列がデータベースで識別されない名前の場合でも関数が識別できるように、列属性を設定する必要があります。
ネーミング規則は、次のとおりです。
子のネストした表のSETID(SID)列
SETID列は必須です。ダミーの名前を使用してOCI_ATTR_NAMEを設定します。これは、APIでは、ユーザーがシステム名を認識していないとみなしているためです。次に、これがSID列であることを示すために、OCI_ATTR_DIRPATH_SIDを使用して列属性を設定します。
オブジェクト表のオブジェクトID(OID)列
次の場合、オブジェクトIDは必須です。
オブジェクトIDがシステム生成の場合。
列名にダミーの名前(たとえば、cust_oid)を使用します。
OCI_ATTR_DIRPATH_OIDで列属性を設定します。その結果、ダミーの名前を持つ列が複数ある場合にも、システム生成のOIDを表す列を識別できます。
オブジェクトIDが主キー・ベースの場合。
列名にはダミーの名前を使用できません。したがって、OCI_ATTR_DIRPATH_OIDを使用してその列属性を設定する必要はありません。
SQL文字列の引数
OCI_ATTR_NAMEで属性の列名を設定します。
SQL文字列の引数の順序は、重要ではありません。SQL文字列で使用されている順序と一致させる必要はありません。
SQL文字列の引数には、次のネーミング規則が適用されます。
引数名は、SQL文字列で使用されているバインド変数名と内容が一致している必要がありますが、大/小文字区別を一致させる必要はありません。たとえば、SQL文字列がsubstr(:INPUT_STRING, 3, 5)の場合は、引数名をinput_stringにできます。
1つの引数がSQL文字列で繰り返し使用される場合、それを一度宣言した後は、1つの引数としてカウントできます。
REF引数
OCI_ATTR_NAMEで属性の列名を設定します。
REF引数の順序は重要です。
参照表の名前が指定されている場合は、その名前を最初のREF引数に指定します。
オブジェクトIDは、システム生成または主キー・ベースに関係なく、次のREF引数に指定します。
REF引数には次のネーミング規則が適用されます。
参照表名の引数の場合は、その列名にref-tblなどの仮の名前を使用します。
システム生成OIDの引数に対しては、列名にsys-OIDなどの仮の名前を使用します。注意: この列は、引数として使用され、ロード対象の列としては使用されないため、OCI_ATTR_DIRPATH_OIDで設定しないでください。
主キー・ベースのオブジェクトIDに対しては、ロード対象のすべての主キー列をリストします。OIDに対してダミーの名前を作成する必要はありません。コンポーネント列名は、指定されている場合(次のショート・カットのステップを参照)、任意の順序で指定できます。
ショート・カットを使用する場合は、オブジェクトIDに属性列名を設定しないでください。
ショート・カット − システムOIDベースのREF列をロードする場合は、列名に名前を設定しないでください。名前はAPIによって判断されます。ただし、外部データ型などの他の列属性は、プログラマが設定する必要があります。
主キーREF列をロードしており、その主キーが複数の列で構成されている場合、ショート・カットはそれぞれの列名に設定されません。ただし、外部データ型など他の列属性は、ユーザーが設定する必要があります。
|
注意: コンポーネント列名がNULLの場合は、APIコードによって、主キーに定義された位置または順序で列名が決定されます。したがって、名前以外の列属性を設定する場合は、その属性がコンポーネントの列に適切な順序で設定されていることを確認してください。 |
列がオブジェクト、SQL文字列またはREFの場合は、OCI_HTYPE_DIRPATH_FN_COL_ARRAYハンドル型を使用します。構造体OCIDirPathColArrayは、スカラー列と非スカラー列両方の場合で同じです。
関数コンテキストに子の列配列を割り当てるには、次のようにします。
OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
OCIDirPathColArray *dpfnca; /* direct path function column array */
sword error;
error = OCIHandleAlloc((void *)dpfnctx, (void **)&dpfnca,
OCI_HTYPE_DIRPATH_FN_COL_ARRAY,
(size_t)0, (void **)0);