プライマリ・コンテンツに移動
Oracle® Call Interfaceプログラマーズ・ガイド
12c リリース1 (12.1)
B72465-07
目次へ移動
目次
索引へ移動
索引

前
次

12 OCIのオブジェクト・リレーショナル・データ型

この章では、OCIデータ型のマッピング関数および操作関数で操作できる各データ型の用途と構造について説明します。

また、関数をグループ別にまとめ、使用可能な関数とその目的のリストを示します。さらに、OCIアプリケーションのバインド操作と定義操作でこれらのデータ型を使用する方法も説明します。

この章は、次の項目で構成されています。

オブジェクトに対するOCI関数の概要

OCIデータ型のマッピング関数および操作関数を使用すると、事前定義済のOracle Cデータ型のインスタンスを操作できます。

これらのデータ型は、Oracle Databaseのオブジェクト型など、ユーザー定義のデータ型の属性を表現するために使用します。

OCIの各関数グループは、特定のネーミング規則によって区別されます。たとえば、データ型のマッピング関数および操作関数は、関数名が接頭辞OCIで始まり、その後にデータ型が続くため、簡単に認識できます(例: OCIDateFromText()およびOCIRawSize())。後述するように、名前はさらに特定の型のデータを操作する関数グループに分類できます。

これらの関数を操作する事前定義済のOracle C型は、接頭辞OCIで始まる名前でも区別できます(例: OCIDateOCIString)。

データ型のマッピング関数および操作関数は、アプリケーションで、Oracle Databaseに格納されたオブジェクト、またはSQL問合せで取り出されたオブジェクトの属性を操作、バインドまたは定義する必要がある場合に使用します。取り出したオブジェクトはクライアント側のオブジェクト・キャッシュに格納されます。

OCIクライアントは、バインドまたは定義操作を実行する前に記述子を割り当てる必要があります。OCIStmtExecute()およびOCIStmtFetch2()は、記述子が OCIDescriptorAlloc()によって割り当てられていない場合、これらの記述子にはメモリーを割り当てることはできません。

これらの関数は、OCIアプリケーションをオブジェクト・モードで実行している間にのみ有効です。OCIのオブジェクト・モードでの初期化、およびオブジェクトにアクセスして操作するOCIアプリケーションの作成の詳細は、「環境およびオブジェクト・キャッシュの初期化について」を参照してください。

注意:

OCIDateなどのオブジェクト型に対する操作では、結果のアドレスを演算子のアドレスと同じにできます。

関連項目:

Oracleデータ型のCへのマッピングについて

Oracleには、表を作成し、ユーザー定義のデータ型(オブジェクト型を含む)を指定できる、一連の事前定義済のデータ型があります。

オブジェクト型はOracle Databaseの機能を拡張するものであり、オブジェクト型を使用すると、処理対象のデータの型を正確にモデル化したデータ型を作成できます。そのため、プログラマは、より効率的で簡単なデータ・アクセスができます。

NCHARおよびNVARCHAR2はオブジェクトの属性として使用でき、CではOCIString *にマップされます。

データベースの表およびオブジェクト型は、Oracleが供給するデータ型に基づいています。データベースの表およびオブジェクト型は、SQL文で作成し、VARCHAR2NUMBERなどの特定のOracle内部データ型を使用して格納します。たとえば、次のSQL文では、ユーザー定義のaddressデータ型と、そのデータ型のインスタンスを格納するオブジェクト表を作成します。

CREATE TYPE address AS OBJECT
(street1    varchar2(50),
street2     varchar2(50),
city        varchar2(30),
state       char(2),
zip         number(5));
CREATE TABLE address_table OF address;

この新しいaddress型を使用して、次のようなオブジェクト列を持つ標準表を作成したとします。

CREATE TABLE employees
(name         varchar2(30),
birthday      date,
home_addr     address);

OCIアプリケーションでは、SQL文に対応付けられた、簡単なバインドおよび定義操作を使用して、情報をemployees表のnameおよびbirthdayの列で操作できます。オブジェクトの属性として格納されている情報にアクセスするには、いくつかの追加ステップが必要です。

OCIアプリケーションでは、まずオブジェクトをC言語書式で表現する手段が必要です。そのためには、Object Type Translator (OTT)を使用して、ユーザー定義型のC構造体表現を生成します。生成した構造体の要素には、Oracleのデータ型をC言語にマッピングしたデータ型が含まれます。

その他のC型としてOCIIndがあります。これは、オブジェクト型の属性に対応するNULLインジケータ情報を表現するために使用します。

この項には次のトピックが含まれます。「OCI型マッピングの方法論」

関連項目:

  • オブジェクト属性の型として使用できるOracleの型と、対応するCマッピングについては、表15-1を参照してください。

  • OTTの使用例および詳細は、「OCIでのObject Type Translatorの使用」を参照してください

OCI型マッピングの方法論

事前定義済のOracle型についてマッピングを指定する場合、Oracleでは独特の設計方針に従ってきました。カレント・システムには、次のメリットがあります。

  • OCINumberのようなデータ型の実際の表現は、クライアントのアプリケーションでは不透明で、データ型は事前に定義済の一連の関数によって操作されます。これによって、将来改善する際にも、ユーザー・コードを中断せずに内部表現を変更できます。

  • オブジェクト指向パラダイムに従った実装がなされています。このパラダイムではクラスの実装の詳細は隠されており、見えるのは必要な操作のみです。

  • この実装方法はプログラマにとって有利です。Oracleの数値で提供されるOracle数値変数を、精度を落とすことなく操作するCプログラムを記述する場合について考えてみます。Oracle Databaseリリース7でこの操作を実行するには、SELECT ... FROM DUAL文を発行する必要があります。以降のリリースでは、OCINumber*()関数をコールするのみです。

OCIでのCデータ型の操作について

OCIでCデータ型を操作する方法と、各種の関数の接頭辞、関数名の例および関数の操作対象のデータ型を示します。

OCIアプリケーションで、2つの整変数を合計して結果を第3の変数に格納するという非常に簡単なデータ操作を行うとします。

int    int_1, int_2, sum;
...
/* some initialization occurs */
...
sum = int_1 + int_2;

C言語は、integerのような単純な型に対する一連の事前定義済操作を提供します。ただし、表15-1に示されているCデータ型は、C言語の単純な基本形ではありません。OCIStringおよびOCINumberのような型は、実際は特定のOracle定義の内部構造を持つ構造体です。単に、2つのOCINumberを合計して、その値を第3の変数に格納することはできません。

次の内容は、有効ではありません。

OCINumber    num_1, num_2, sum;
...
/* some initialization occurs */
...
sum = num_1 + num_2;           /* NOT A VALID OPERATION */

このような新しいデータ型を操作するための関数が、OCIデータ型のマッピング関数および操作関数です。たとえば、この例でOCINumberを加算するには、OCINumberAdd()関数を使用します。

OCINumber    num_1, num_2, sum;
...
/* some initialization occurs */
...
OCINumberAdd(errhp, &num_1, &num_2, &sum): /* errhp is error handle */

OCIには、新規データ型をそれぞれ操作する関数があります。関数の名前から、その関数で操作するデータ型がわかります。最初の3文字OCIは、関数がOCIの一部であることを示します。関数名の次の部分は、関数で操作するデータ型を示します。表12-1は、各種の関数の接頭辞、関数名の例および関数の操作対象のデータ型を示しています。

図12-1 関数の接頭辞の例

関数の接頭辞 操作対象
OCIColl
OCICollGetElem()
OCIColl, OCIIter, OCITable, OCIArray
OCIDate
OCIDateDaysBetween()
OCIDate
OCIDateTime
OCIDateTimeSubtract()
OCIDate, OCIDateTime
OCIInterval
OCIIntervalToText()
OCIInterval
OCIIter
OCIIterInit()
OCIIter
OCINumber
OCINumberAdd()
OCINumber
OCIRaw
OCIRawResize()
OCIRaw *
OCIRef
OCIRefAssign()
OCIRef *
OCIString
OCIStringSize()
OCIString *
OCITable
OCITableLast()
OCITable *

各データ型の構造については、そのデータ型を操作対象にする関数のリストとともに、この章で後述します。

この項には次のトピックが含まれます。「Oracle数値操作の精度」

Oracle数値操作の精度

Oracleの数値の精度は、10進数で38桁です。Oracleの数値操作は、次の例外を除いて、全桁で行います。

  • 逆三角関数の精度は、10進数で28桁です。

  • 三角関数を含むその他の超越関数の精度は、およそ10進数で37桁です。

  • システム固有の浮動小数点型との間の変換では、適切な浮動小数点型の精度になり、10進数で38桁を超えることはありません。

日付(OCIDate)

Oracleの日付書式は、不透明なC構造体であるOCIDate型でCにマップされます。構造体の要素は日付の年、月、日、時間、分および秒を表します。

適切なOCI関数を使用すると、特定の要素を設定および取出しできます。

OCIDateデータ型は、バインド・コールまたは定義コールで、外部型コードSQLT_ODTを使用して直接バインドまたは定義できます。

特に明記されていないかぎり、これらの関数コールでのdateという用語は、型OCIDateの値を示します。

関連項目:

すべての関数のプロトタイプと説明は、「OCIのデータ型マッピング関数および操作関数」を参照してください

この項には次のトピックが含まれます。「日付の例」

日付の例

例12-1は、OCIコールを使用して、OCIDate型の属性を操作する方法の例を示しています。この例では、OCIEnvおよびOCIErrorは、「OCI環境の初期化」の説明に従って初期化されているとします。確保の詳細は、「オブジェクト・キャッシュ操作」を参照してください。

出力は次のとおりです。

For: FRIDAY   , OCTOBER   05, 1990
The last day of the month is: WEDNESDAY, OCTOBER   31, 1990
The next Wednesday is: WEDNESDAY, OCTOBER   10, 1990

例12-1 OCIDate型の属性の操作

#define FMT "DAY, MONTH DD, YYYY"
#define LANG "American"
struct person
{
OCIDate start_date;
};
typedef struct person person;

OCIError *err;
person *tim;
sword status;                      /* error status */
uword invalid;
OCIDate last_day, next_day;
text buf[100], last_day_buf[100], next_day_buf[100];
ub4 buflen = sizeof(buf);

/* Pin tim person object in the object cache. */
/*  For this example, assume that
/* tim is pointing to the pinned object. */
/* set the start date of tim */

OCIDateSetTime(&tim->start_date,8,0,0);
OCIDateSetDate(&tim->start_date,1990,10,5);

/* check if the date is valid */
if (OCIDateCheck(err, &tim->start_date, &invalid) != OCI_SUCCESS)
/* error handling code */

if (invalid)
/* error handling code */

/* get the last day of start_date's month */
if (OCIDateLastDay(err, &tim->start_date, &last_day) != OCI_SUCCESS)
/* error handling code */

/* get date of next named day */
if (OCIDateNextDay(err, &tim->start_date, "Wednesday",    strlen("Wednesday"),
&next_day) != OCI_SUCCESS)
/* error handling code */
/* convert dates to strings and print the information */
/* first convert the date itself*/
buflen = sizeof(buf);
if (OCIDateToText(err, &tim->start_date, FMT, sizeof(FMT)-1, LANG,
    sizeof(LANG)-1,             &buflen, buf) != OCI_SUCCESS)
/* error handling code */

/* now the last day of the month */
buflen = sizeof(last_day_buf);
if (OCIDateToText(err, &last_day, FMT, sizeof(FMT)-1, LANG,    sizeof(LANG)-1,
&buflen, last_day_buf) != OCI_SUCCESS)
/* error handling code */

/* now the first Wednesday after this date */
buflen = sizeof(next_day_buf);
if (OCIDateToText(err, &next_day, FMT, sizeof(FMT)-1, LANG,
   sizeof(LANG)-1, &buflen, next_day_buf) != OCI_SUCCESS)
/* error handling code */

/* print the information */
printf("For: %s\n", buf);
printf("The last day of the month is: %s\n", last_day_buf);
printf("The next Wednesday is: %s\n", next_day_buf);

日時および時間隔(OCIDateTime、OCIInterval)

OCIDateTimeデータ型は、Oracleのタイムスタンプのデータ型(TIMESTAMPTIMESTAMP WITH TIME ZONETIMESTAMP WITH LOCAL TIME ZONE)およびANSI DATEデータ型の表現に使用する不透明な構造体です。

適切なOCI関数を使用すると、これらの型(つまり、年、日、小数秒)でのデータの設定または取出しを実行できます。

OCIIntervalデータ型も不透明な構造体で、Oracleの時間隔データ型(INTERVAL YEAR TO MONTHINTERVAL DAY TO SECOND)の表現に使用されます。

バインドまたは定義のコールで、表12-2に示す外部型コードを使用すると、OCIDateTimeOCIIntervalのデータをバインドおよび定義できます。

表12-2 日時および時間隔データ型のバインドと定義

OCIデータ型 データの型 バンド/定義の外部型コード
OCIDateTime

ANSI DATE

SQLT_DATE

OCIDateTime

TIMESTAMP

SQLT_TIMESTAMP

OCIDateTime

TIMESTAMPWITHTIMEZONE

SQLT_TIMESTAMP_TZ

OCIDateTime

TIMESTAMPWITHLOCALTIMEZONE

SQLT_TIMESTAMP_LTZ

OCIInterval

INTERVALYEARTOMONTH

SQLT_INTERVAL_YM

OCIInterval

INTERVALDAYTOSECOND

SQLT_INTERVAL_DS

通常、OCIDateTimeデータを操作する関数は、OCIDateデータにも有効です。

この項には次のトピックが含まれます:

関連項目:

日時関数について

次の関数は、OCIDateTimeの値を操作します。この関数の中には、日時と時間隔の値に関する算術演算を行う関数もあります。また、特定の日時型に対してのみ動作する関数もあります。可能な型は、次のとおりです。

  • SQLT_DATE - DATE

  • SQLT_TIMESTAMP - TIMESTAMP

  • SQLT_TIMESTAMP_TZ: TIMESTAMP WITH TIME ZONE

  • SQLT_TIMESTAMP_LTZ: TIMESTAMP WITH LOCAL TIME ZONE

特定の関数に有効な入力型の詳細は、表12-3に示す各関数の説明を参照してください。

表12-3 日時関数

関数 用途

「OCIDateTimeAssign()」

日時の割当てを実行します。

「OCIDateTimeCheck()」

指定の日付が有効かどうかをチェックします。

「OCIDateTimeCompare()」

2つの日時値を比較します。

「OCIDateTimeConstruct()」

日時記述子を作成します。

「OCIDateTimeConvert()」

ある日時型を別の日時型に変換します。

「OCIDateTimeFromArray()」

日付が含まれている配列をOCIDateTime記述子に変換します。

「OCIDateTimeFromText()」

指定された書式に従って、指定の文字列をOCIDateTime記述子のOracle日時型に変換します。

「OCIDateTimeGetDate()」

日時値の日付部分(年、月、日)を取得します。

「OCIDateTimeGetTime()」

日時値の時刻部分(時間、分、秒、小数秒)を取得します。

「OCIDateTimeGetTimeZoneName()」

日時値のタイム・ゾーン名部分を取得します。

「OCIDateTimeGetTimeZoneOffset()」

日時値のタイム・ゾーン(時間、分)部分を取得します。

「OCIDateTimeIntervalAdd()」

日時に時間隔を加算して、結果の日時を生成します。

「OCIDateTimeIntervalSub()」

日時から時間隔を減算して、その結果を日時に格納します。

「OCIDateTimeSubtract()」

2つの日時を入力値にして、その差異を時間隔に格納します。

「OCIDateTimeSysTimeStamp()」

現行のシステム日付および時刻を、タイム・ゾーン付きタイムスタンプとして取得します。

「OCIDateTimeToArray()」

OCIDateTime記述子を配列に変換します。

「OCIDateTimeToText()」

指定された日付を指定の書式の文字列に変換します。

「OCIDateZoneToZone()」

あるタイム・ゾーンの日付を別のタイム・ゾーンの日付に変換します。

日時の例

例12-2のコード・フラグメントは、OCIDateTimeデータ型を使用してTIMESTAMP WITH LOCAL TIME ZONE列からデータを選択する方法を示しています。

例12-2 OCIDateTime型の属性の操作

...

/* allocate the program variable for storing the data */
OCIDateTime *tstmpltz = (OCIDateTime *)NULL;

/* Col1 is a time stamp with local time zone column */
OraText *sqlstmt = (OraText *)"SELECT col1 FROM foo";

/* Allocate the descriptor (storage) for the data type */
status = OCIDescriptorAlloc(envhp,(void  **)&tstmpltz, OCI_DTYPE_TIMESTAMP_LTZ,
         0, (void  **)0);
....

status = OCIStmtPrepare (stmthp, errhp, sqlstmt, (ub4)strlen ((char *)sqlstmt),
         (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT);

/* specify the define buffer for col1 */
status = OCIDefineByPos(stmthp, &defnp, errhp, 1, &tstmpltz, sizeof(tstmpltz),
         SQLT_TIMESTAMP_LTZ, 0, 0, 0, OCI_DEFAULT);

/* Execute and Fetch */
OCIStmtExecute(svchp, stmthp, errhp, 1, 0,(OCISnapshot *) NULL,
         (OCISnapshot *)NULL, OCI_DEFAULT)

At this point tstmpltz contains a valid time stamp with local time zone data. You
can get the time zone name of the datetime data using:

status = OCIDateTimeGetTimeZoneName(envhp, errhp, tstmpltz, (ub1 *)buf,
         (ub4 *)&buflen);
...

時間隔関数について

時間隔関数をリストし、説明します。

例12-4に示す関数は、時間隔データのみを操作します。対象となる時間隔の型の指定が必要な場合があります。可能な型は、次のとおりです。

  • SQLT_INTERVAL_YM: 年から月までの時間隔

  • SQLT_INTERVAL_DS: 日から秒までの時間隔

詳細は、各関数の説明を参照してください。

表12-4 時間隔関数

関数 用途

OCIIntervalAdd()

2つの時間隔を加算して、その結果の時間隔を生成します。

OCIIntervalAssign()

ある時間隔を別の時間隔にコピーします。

OCIIntervalCheck()

時間隔の妥当性をチェックします。

OCIIntervalCompare()

2つの時間隔を比較します。

OCIIntervalDivide()

時間隔をOracle NUMBERで除算して、時間隔を生成します。

OCIIntervalFromNumber()

Oracle NUMBERを時間隔に変換します。

OCIIntervalFromText()

時間隔文字列が指定されている場合、その文字列で表現される時間隔を変換します。

OCIIntervalFromTZ()

タイム・ゾーン形式の入力文字列が指定されている場合、時間隔を戻します。

OCIIntervalGetDaySecond()

時間隔から日、時、分、秒の値を取得します。

OCIIntervalGetYearMonth()

時間隔から年と月を取得します。

OCIIntervalMultiply()

時間隔をOracle NUMBERで乗算して、時間隔を生成します。

OCIIntervalSetDaySecond()

時間隔に日、時、分、秒を設定します。

OCIIntervalSetYearMonth()

時間隔に年と月を設定します。

OCIIntervalSubtract()

2つの時間隔を減算し、その結果を時間隔に格納します。

OCIIntervalToNumber()

時間隔をOracle NUMBERに変換します。

OCIIntervalToText()

時間隔が指定されている場合、その時間隔を表現する文字列を生成します。

関連項目:

各関数の名前と用途のリストおよび詳細は、「OCIの日付関数、日時関数および時間隔関数」を参照してください

数値(OCINumber)

OCINumberデータ型は、Oracleの数値データ型(NUMBERFLOATDECIMALなど)の表現に使用する不透明な構造体です。

この型は、バインド・コールまたは定義コールで外部型コードSQLT_VNUを使用して、バインドまたは定義できます。

特に明記されていないかぎり、これらの関数コールでのnumberという用語は、型OCINumberの値を示します。

この項には次のトピックが含まれます。「OCINumberの例」

関連項目:

すべてのOCI NUMBER関数のプロトタイプと説明は、表19-11を参照してください。

OCINumberの例

例12-3のコード・フラグメントは、OCINumber型の属性を操作する方法の例を示しています。例12-4のコード・フラグメントは、OCIDescribeAny()コールから戻されたOCINumber形式の値を符号なし整数に変換する方法を示します。

例12-4は、OCINumber形式でOCIDescribeAny()コールから戻された数値型(OCI_ATTR_MAXOCI_ATTR_MINなど)を符号なしC整数に変換する方法を示します。

例12-3 OCINumber型の属性の操作

/* Example 1  */
struct person
{
OCINumber sal;
};
typedef struct person person;
OCIError *err;
person* steve;
person* scott;
person* jason;
OCINumber  *stevesal;
OCINumber  *scottsal;
OCINumber *debsal;
sword   status;
int     inum;
double  dnum;
OCINumber ornum;
text   buffer[21];
ub4     buflen;
sword   result;

/* For this example, assume OCIEnv and OCIError are initialized. */
/* For this example, assume that steve, scott, and jason are pointing to
  person objects that have been pinned in the object cache. */
stevesal = &steve->sal;
scottsal = &scott->sal;
debsal = &jason->sal;

/* initialize steve's salary to be $12,000 */
inum = 12000;
status = OCINumberFromInt(err, &inum, sizeof(inum), OCI_NUMBER_SIGNED,
    stevesal);
if (status != OCI_SUCCESS)  /* handle error from OCINumberFromInt */;

/* initialize scott's salary to be the same as steve's */
OCINumberAssign(err, stevesal, scottsal);

/* initialize jason's salary to be 20% more than steve's */
dnum = 1.2;
status = OCINumberFromReal(err, &dnum, sizeof(dnum), &ornum);
if (status != OCI_SUCCESS)  /* handle error from OCINumberFromReal */;
status = OCINumberMul(err, stevesal, &ornum, debsal);
if (status != OCI_SUCCESS)  /* handle error from OCINumberMul */;

/* give scott a 50% raise */
dnum = 1.5;
status = OCINumberFromReal(err, &dnum, sizeof(dnum), &ornum);
if (status != OCI_SUCCESS)  /* handle error from OCINumberFromReal */;
status = OCINumberMul(err, scottsal, &ornum, scottsal);
if (status != OCI_SUCCESS)  /* handle error from OCINumberMul */;

/* double steve's salary */
status = OCINumberAdd(err, stevesal, stevesal, stevesal);
if (status != OCI_SUCCESS)  /* handle error from OCINumberAdd */;

/* get steve's salary in integer */
status = OCINumberToInt(err, stevesal, sizeof(inum), OCI_NUMBER_SIGNED, &inum);
if (status != OCI_SUCCESS)  /* handle error from OCINumberToInt */;

/* inum is set to 24000 */
/* get jason's salary in double */
status = OCINumberToReal(err, debsal, sizeof(dnum), &dnum);
if (status != OCI_SUCCESS)  /* handle error from OCINumberToReal */;

/* dnum is set to 14400 */
/* print scott's salary as DEM0001'8000.00 */
buflen = sizeof(buffer);
status = OCINumberToText(err, scottsal, (text *)"C0999G9999D99", 13,
         (text *)"NLS_NUMERIC_CHARACTERS='.'' NLS_ISO_CURRENCY='Germany'",
         54, &buflen, (text *)buffer);
if (status != OCI_SUCCESS)  /* handle error from OCINumberToText */;
printf("scott's salary = %s\n", buffer);

/* compare steve and scott's salaries */
status = OCINumberCmp(err, stevesal, scottsal, &result);
if (status != OCI_SUCCESS)  /* handle error from OCINumberCmp */;

/* result is positive */
/* read jason's new salary from string */
status = OCINumberFromText(err, (text *)"48'000.00", 9, (text
*)"99G999D99", 9,
    (text *)"NLS_NUMERIC_CHARACTERS='.''", 27, debsal);
if (status != OCI_SUCCESS)  /* handle error from OCINumberFromText */;
/* jason's salary is now 48000.00 */

例12-4 OCIDescribeAny()コールから戻されたOCINumber形式の値の符号なし整数への変換

/* Example 2 */
ub4  max_seq_val  = 0;
ub1 *max_valp     = NULL;
ub4  max_val_size;
OCINumber max_val;
    OCINumberSetZero(_errhp, &max_val);
    OCIParam* parmdp = 0;
    status = OCIAttrGet ((void *)_dschp, (ub4)OCI_HTYPE_DESCRIBE, &parmdp, 0,
                         (ub4)OCI_ATTR_PARAM, _errhp);
if (isError (status, _errhp))
{
return 0;
}
status = OCIAttrGet ((void *)parmdp, (ub4)OCI_DTYPE_PARAM, &max_valp,
                     &max_val_size, (ub4)OCI_ATTR_MAX, _errhp);
//create an OCINumber object from the ORACLE NUMBER FORMAT
max_val.OCINumberPart[0] = max_val_size; //set the length byte
memcpy(&max_val.OCINumberPart[1], max_valp, max_val_size); //copy the actual bytes
//now convert max_val to an unsigned C integer, max_seq_val 
status = OCINumberToInt(_errhp, &max_val, sizeof(max_seq_val),
                        OCI_NUMBER_UNSIGNED, &max_seq_val);

固定長または可変長文字列(OCIString)

固定長または可変長の文字列データは、Cプログラムに対してOCIString *として表現されます。

文字列の長さには、NULL文字は含まれていません。

OCIString *型の変数のバインドと定義には、外部型コードSQLT_VSTを使用します。

この項には次のトピックが含まれます:

関連項目:

すべての文字列関数のプロトタイプと説明は、表19-16を参照してください。

文字列関数について

表12-5は、Cのプログラマが文字列のインスタンスを操作できる関数を示しています。

表12-5 文字列関数

関数 用途

「OCIStringAllocSize()」

文字列の割当てメモリー・サイズをコード・ポイント(Unicode)またはバイト単位で取得します。

「OCIStringAssign()」

文字列を別の文字列に割り当てます。

「OCIStringAssignText()」

ソース・テキスト文字列をターゲット文字列に割り当てます。

「OCIStringPtr()」

指定の文字列のテキストへのポインタを取得します。

「OCIStringResize()」

指定の文字列のメモリー・サイズを変更します。

「OCIStringSize()」

指定の文字列のサイズを取得します。

文字列の例

例12-5では、テキスト文字列を文字列に代入し、文字列の文字列部分へのポインタと文字列サイズを取得して、出力します。

OCIStringAssignText()において、vstring1パラメータを渡すために二重間接演算が使用されていることに注意してください。

例12-5 OCIString型の属性の操作

OCIEnv       *envhp;
OCIError     *errhp;
OCIString     *vstring1 = (OCIString *)0;
OCIString     *vstring2 = (OCIString *)0;
text          c_string[20];
text         *text_ptr;
sword        status;

strcpy((char *)c_string, "hello world");
/* Assign a text string to an OCIString */
status = OCIStringAssignText(envhp, errhp, c_string,
      (ub4)strlen((char *)c_string),&vstring1);
/* Memory for vstring1 is allocated as part of string assignment */

status = OCIStringAssignText(envhp, errhp, (text *)"hello again",
       (ub4)strlen("This is a longer string."),&vstring1);
/* vstring1 is automatically resized to store the longer string */

/* Get a pointer to the string part of vstring1 */
text_ptr = OCIStringPtr(envhp, vstring1);
/* text_ptr now points to "hello world" */
printf("%s\n", text_ptr);

ロー(OCIRaw)

可変長ロー・データは、OCIRaw *データ型を使用してCで表現されます。

OCIRaw *型の変数のバインドと定義には、外部型コードSQLT_LVBを使用します。

この項には次のトピックが含まれます:

関連項目:

すべてのロー関数のプロトタイプと説明は、表19-14を参照してください。

ロー関数について

表12-6は、OCIRawの操作を実行する関数を示しています。

表12-6 ロー関数

関数 用途

「OCIRawAllocSize()」

ロー・メモリーの割り当てられたサイズ(バイト単位)を取得します。

「OCIRawAssignBytes()」

ロー・データ(ub1 *)をOCIRaw *に代入します。

「OCIRawAssignRaw()」

1つのOCIRaw *を別のOCIRaw *に代入します。

「OCIRawPtr()」

ロー・データへのポインタを取得します。

「OCIRawResize()」

可変長ロー・データのメモリーのサイズ変更を行います。

「OCIRawSize()」

ロー・データのサイズを取得します。

ローの例

例12-6は、ロー・データのブロックを設定し、そのデータへのポインタを取得する方法を示しています。

OCIRawAssignBytes()のコールで二重間接演算を使用していることに注意してください。

例12-6 OCIRaw型の属性の操作

OCIEnv      *envhp;
OCIError    *errhp;
sword       status;
ub1         data_block[10000];
ub4         data_block_len = 10000;
OCIRaw      *raw1 = (OCIRaw *) 0;
ub1 *raw1_pointer;

/* Set up the RAW */
/* assume 'data_block' has been initialized */
status = OCIRawAssignBytes(envhp, errhp, data_block, data_block_len,
&raw1);

/* Get a pointer to the data part of the RAW */
raw1_pointer = OCIRawPtr(envhp, raw1);

コレクション(OCITable、OCIArray、OCIColl、OCIIter)

Oracle Databaseには、可変長配列(VARRAY)とネストした表の2種類のコレクションがあります。Cアプリケーションでは、VARRAYはOCIArray *と表現され、ネストした表は、OCITable *と表現されます。

これらの両方のデータ型は(後述するOCICollOCIIterと同様に)、不透明な構造体です。

様々な汎用コレクション関数により、コレクション・データを操作できます。汎用コレクション関数は、VARRAYとネストした表の両方に使用できます。また、ネストした表固有の一連の関数もあります。

VARRAYまたはネストした表のインスタンスは、OCIObjectNew()を使用して割り当て、OCIObjectFree()を使用して解放できます。

関連項目:

汎用コレクション関数

Oracle Databaseには、可変長配列(VARRAY)とネストした表の2種類のコレクションがあります。

VARRAYとネストした表は、どちらも汎用コレクション型のサブタイプとみなすことができます。

Cでは、汎用コレクションをOCIColl *、VARRAYをOCIArray *、ネストした表をOCITable *と表現します。Oracleには、汎用コレクションを操作するための一連の関数群(OCIColl *など)があります。これらの関数は、OCICollGetElem()のように接頭辞OCICollで始まります。OCIColl*()関数をコールして、VARRAYとネストした表を操作することもできます。

汎用コレクション関数は、2つの主なカテゴリにグループ化できます。

  • VARRAYまたはネストした表のデータを操作するグループ

  • コレクション・イテレータを使用してコレクションをスキャンするグループ

汎用コレクション関数は、VARRAYを操作する関数の完全な集合です。その他の関数は、特にネストした表で操作するための関数です。これらの関数は、OCITableExists().のように接頭辞OCITableで識別できます

注意:

コレクション関数に渡された索引は、0 (ゼロ)が基数です。

コレクション・データ操作関数について

表12-7は、コレクション・データを操作する汎用関数を示しています。

表12-7 コレクション関数

関数 用途

「OCICollAppend()」

コレクションの最後に要素を追加します。

「OCICollAssign()」

1つのコレクションを別のコレクションに割り当てます。

「OCICollAssignElem()」

指定の索引位置に要素を割り当てます。

「OCICollGetElem()」

索引位置の指定時に要素へのポインタを取得します。

「OCICollGetElemArray()」

コレクションから要素の配列を取得します。

「OCICollIsLocator()」

コレクションがロケータベースであるかどうかを示します。

「OCICollMax()」

コレクションの上限を取得します。

「OCICollSize()」

コレクションのカレント・サイズを取得します。

「OCICollTrim()」

コレクションの終わりからn個の要素を切り捨てます。

コレクション・スキャン関数について

表12-8は、コレクション・イテレータを使用してコレクションをスキャンできる汎用関数を示しています。イテレータは、OCIIter型であり、最初にOCIIterCreate()をコールして作成します。

表12-8 コレクション・スキャン関数

関数 用途

「OCIIterCreate()」

コレクションの要素をスキャンするためのイテレータを作成します。

「OCIIterDelete()」

コレクション・イテレータを削除します。

「OCIIterGetCurrent()」

イテレータが指し示すカレント要素へのポインタを取得します。

「OCIIterInit()」

イテレータを初期化して指定のコレクションをスキャンします。

「OCIIterNext()」

次のイテレータ・コレクション要素へのポインタを取得します。

「OCIIterPrev()」

直前のイテレータ・コレクション要素へのポインタを取得します。

VARRAY/コレクション・イテレータの例

例12-7では、コレクション・イテレータを作成し、それを使用してVARRAY (可変長配列)をスキャンします。

例12-7 コレクション・データ操作関数の使用

OCIEnv       *envhp;
OCIError     *errhp;
text         *text_ptr;
sword        status;
OCIArray     *clients;
OCIString    *client_elem;
OCIIter      *iterator;
boolean      eoc;
void         *elem;
OCIInd       *elemind;

/* Assume envhp, errhp have been initialized */
/* Assume clients points to a varray */

/* Print the elements of clients */
/* To do this, create an iterator to scan the varray */
status = OCIIterCreate(envhp, errhp, clients, &iterator);

/* Get the first element of the clients varray */
printf("Clients' list:\n");
status = OCIIterNext(envhp, errhp, iterator, &elem,
                    (void  **) &elemind, &eoc);

while (!eoc && (status == OCI_SUCCESS))
{
  client_elem = *((OCIString **)elem);
                             /* client_elem points to the string */

 /*
    the element pointer type returned by OCIIterNext() through 'elem' is

    the same as that of OCICollGetElem(). See OCICollGetElem() for
    details.  */

  /*
    client_elem points to an OCIString descriptor, so to print it out,
    get a pointer to where the text begins
  */
  text_ptr = OCIStringPtr(envhp, client_elem);

  /*
    text_ptr now points to the text part of the client OCIString, which
is a
NULL-terminated string
  */
  printf("  %s\n", text_ptr);
  status = OCIIterNext(envhp, errhp, iterator, &elem,
                      (void  **)&elemind, &eoc);
}

if (status != OCI_SUCCESS)
{
  /* handle error */
}

/* destroy the iterator */
status = OCIIterDelete(envhp, errhp, &iterator);

ネストした表の操作関数について

その名前が示すように、1つの表はネストしている、つまり変数、属性、パラメータまたは列として別の表の中に含まれている場合があります。

ネストした表には、OCITableDelete()関数で削除された要素が含まれている場合があります。

たとえば、10個の要素を指定して作成した表があり、0から4と9の索引を持つ要素をOCITableDelete()で削除したとします。既存の最初の要素は要素5になり、既存の最後の要素は要素8になります。

前述のように、汎用コレクション関数を使用しても、ネストした表へのマッピングやネストした表の操作ができます。さらに、表12-9は、ネストした表専用の関数を示しています。ネストした表専用の関数は、VARRAYでは使用できません。

表12-9 ネストした表の関数

関数 用途

OCITableDelete()

指定の索引位置にある要素を削除します。

OCITableExists()

指定の索引位置に要素が存在するかどうかをテストします。

OCITableFirst()

表の最初の既存要素の索引を戻します。

OCITableLast()

表の最後の既存要素の索引を戻します。

OCITableNext()

表の次の既存要素の索引を戻します。

OCITablePrev()

表の直前の既存要素の索引を戻します。

OCITableSize()

削除した要素を除いた表のサイズを戻します。

この項には次のトピックが含まれます。「ネストした表の要素への順序付け」

ネストした表の要素への順序付け

ネストした表がオブジェクト・キャッシュにフェッチされた場合、その要素には、0 (ゼロ)から始まり要素数から1を引いた数で終わる順序が一時的に付けられます。たとえば、40個の要素を持つ表では、0から39まで順序付けが行われます。

これらの位置序数を使用して、要素の値のフェッチと代入が行われます(たとえば、要素iへのフェッチや、要素jへの代入など。ijは、指定の表の有効な位置序数です)。

表をデータベースにコピーすると、一時的な順序付けは失われます。表の要素に対して削除の操作を行うことがあります。削除操作により、一時的なが作成されます。つまり、削除操作では、残りの表要素の位置序数は変更されません。

ネストした表のロケータ

ネストした表のロケータを取り出すことができます。ロケータはコレクション値へのハンドルのようなもので、検索時に存在するデータベース・スナップショットについての情報を含みます。

このスナップショット情報は、後にロケータを使用してコレクション要素がフェッチされるときに、データベースでコレクション値の正しいインスタンス化を取り出すために役立ちます。

LOBロケータとは異なり、コレクション・ロケータはコレクション・インスタンスの変更には使用できず、正しいデータを特定するだけです。ロケータを使用すると、アプリケーションは、非常に大規模な場合もある全コレクションを検索しなくても、ハンドルをネストした表に戻すことができます。

コレクション列または属性をフェッチするときにロケータが戻される必要がある場合、ユーザーは、RETURN AS LOCATOR指定を使用して、表がいつ作成されるかを指定します。

コレクションがロケータベースであるかどうかを判断するには、OCICollIsLocator()関数を使用します。

マルチレベル・コレクション型について

コレクション要素自体が直接的または間接的に別のコレクション型である場合があります。

マルチレベル・コレクション型とは、このようなトップレベルのコレクション型に付けられた名前です。

マルチレベル・コレクションには、次のような特性があります。

  • 他のコレクション型の集まりである場合があります。

  • コレクション属性を持つオブジェクトの集まりである場合があります。

  • ネスト・レベルの数に制限がありません。

  • VARRAYとネストした表の組合せを含めることができます。

  • 表の列として使用できます。

OCIルーチンは、マルチレベル・コレクションを処理します。次のルーチンは、パラメータ*elemOCIColl*を戻すことができるため、このパラメータは任意のコレクションのルーチンで使用できます。

  • OCICollGetElem()

  • OCIIterGetCurrent()

  • OCIIterNext()

  • OCIIterPrev()

次の関数は、コレクション要素を取得し、それを既存のコレクションに追加します。要素型が別のコレクションの場合、パラメータelemは、OCIColl*となることがあります。

  • OCICollAssignElem()

  • OCICollAppend()

この項には次のトピックが含まれます。「マルチレベル・コレクション型の例」

マルチレベル・コレクション型の例

次の型および表は、例12-8で使用します。

type_1 (a NUMBER, b NUMBER)
NT1 TABLE OF type_1
NT2 TABLE OF NT1

例12-8のコード・フラグメントは、マルチレベル・コレクション全体で反復します。

例12-8 マルチレベル・コレクション・データ操作関数の使用

...
OCIColl *outer_coll;
OCIColl *inner_coll;
OCIIter *itr1, *itr2;
Type_1 *type_1_instance;
..
/* assume that outer_coll points to a valid coll of type NT2 */
checkerr(errhp, OCIIterCreate(envhp, errhp, outer_coll, &itr1));
for(eoc = FALSE;!OCIIterNext(envhp, errhp, itr1, (void  **) &elem,
                               (void  **) &elem_null, &eoc) && !eoc;)
{
   inner_coll = (OCIColl *)elem;
   /* iterate over inner collection.. */
   checkerr(errhp, OCIIterCreate(envhp, errhp, inner_coll, &itr2));
   for(eoc2 = FALSE;!OCIIterNext(envhp, errhp, itr2, (void  **)&elem2,
              (void  **) &elem2_null, &eoc2) && !eoc2;)
       {
        type_1_instance = (Type_1 *)elem2;
        /* use the fields of type_1_instance */
       }
   /* close iterator over inner collection */
   checkerr(errhp, OCIIterDelete(envhp, errhp, &itr2));
}
/* close iterator over outer collection */
checkerr(errhp, OCIIterDelete(envhp, errhp, &itr1));
...

REF (OCIRef)

REF(参照)とは、オブジェクトを識別する識別子です。

これは、一意にオブジェクトを検索する不透明な構造体です。REFによって、オブジェクトは別のオブジェクトを指し示すことができます。

Cアプリケーションでは、OCIRef *REFを表現します。

この項には次のトピックが含まれます:

関連項目:

すべてのREF操作関数のプロトタイプと説明は、表19-15を参照してください。

REF操作関数について

表12-10は、REFの操作を実行する関数を示しています。

表12-10 REF操作関数

関数 用途

「OCIRefAssign()」

1つのREFを別のREFに代入します。

「OCIRefClear()」

REFを消去またはNULL化します。

「OCIRefFromHex()」

16進文字列をREFに変換します。

「OCIRefHexSize()」

REFの16進文字列表現のサイズを戻します。

「OCIRefIsEqual()」

2つのREFが等しいかどうかを比較します。

「OCIRefIsNull()」

REFNULLかどうかをテストします。

「OCIRefToHex()」

REFを16進文字列に変換します。

REFの例

例12-9では、2つのREFNULLかどうかをテストし、両者が等しいかどうかを比較し、一方のREFをもう一方のREFに代入します。OCIRefAssign()のコールで二重間接演算を使用していることに注意してください。

例12-9 REF操作関数の使用

OCIEnv       *envhp;
OCIError     *errhp;
sword        status;
boolean      refs_equal;
OCIRef       *ref1, *ref2;

/* assume REFs have been initialized to point to valid objects */
/*Compare two REFs for equality */
refs_equal = OCIRefIsEqual(envhp, ref1, ref2);
printf("After first OCIRefIsEqual:\n");
if(refs_equal)
   printf("REFs equal\n");
else
   printf("REFs not equal\n");

/*Assign ref1 to ref2 */
status = OCIRefAssign (envhp, errhp, ref1, &ref2);
if(status != OCI_SUCCESS)
/*error handling*/

/*Compare the two REFs again for equality */
refs_equal = OCIRefIsEqual(envhp, ref1, ref2);
printf("After second OCIRefIsEqual:\n");
if(refs_equal)
   printf("REFs equal\n");
else
   printf("REFs not equal\n");

オブジェクト型情報の格納およびアクセス

この項では、OCIデータ型と型記述子について説明します。

この項には次のトピックが含まれます。「記述子オブジェクト」

記述子オブジェクト

ある型をCREATE TYPE文で作成すると、その型はサーバーに格納され、型記述子オブジェクト(TDO)に関連付けられます。さらに、型の各データ属性、型の各メソッド、各メソッドの各パラメータ、およびメソッドが戻す結果について、記述子オブジェクトがデータベースに格納されます。表12-11は、記述子オブジェクトの種類別に、関連付けられているOCIデータ型を示しています。

表12-11 記述子オブジェクト

情報の種類 OCIデータ型

OCIType

型属性、コレクション要素、メソッド・パラメータ、メソッドの結果

OCITypeElem

メソッド

OCITypeMethod

OCI関数の中には(OCIBindObject()およびOCIObjectNew()を含む)、TDOを入力パラメータとして必要とする関数があります。アプリケーションで、その型のTDOをOCIType変数で取得できるOCITypeByName()をコールしてTDOを取得できます。TDOを取得すると、必要に応じて、そのTDOをその他のコールに渡すことができます。

AnyTypeインタフェース、AnyDataインタフェースおよびAnyDataSetインタフェース

AnyTypeインタフェース、AnyDataインタフェースおよびAnyDataSetインタフェースによって、自己記述データをモデル化できます。

異機種間データ型を同じ列に格納し、アプリケーションでそのデータの型を問い合せることができます。

後続の項の説明では、これらの定義が使用されています。

  • 永続型。SQL文CREATE TYPEを使用して作成される型。データベースに永続的に格納されます。

  • 一時型。データベースに永続的には格納されない無名型の記述。必要に応じてプログラムで作成されます。また、必要な場合は、動的方式でアプリケーションの様々なコンポーネント間で型情報をやりとりするのに便利です。

  • 自己記述データ。型情報をその実際の内容とともにカプセル化したデータ。OCIでは、OCIAnyDataデータ型によって、このようなデータがモデル化されます。ほとんどのSQL型のデータ値は、元のデータ値に変換しなおすことができるOCIAnyDataに変換できます。SQLやPL/SQLでは、SYS.ANYDATA型によって、このデータセットがモデル化されます。

  • 自己記述データセット。一連のデータ・インスタンス(すべて同じ型)を型記述とともにカプセル化したもの。すべての型記述が同じである必要があります。OCIでは、OCIDataAnySetデータ型によって、このようなデータがモデル化されます。SQLやPL/SQLでは、SYS.ANYDATASETによって、このようなデータがモデル化されます。

これらの型記述および自己記述データの作成と操作に必要なインタフェースは、OCI (C言語)およびSQLとPL/SQLの両方で使用可能です。次の各項では、関連するOCIインタフェースを説明します。

関連項目:

型インタフェースについて

型インタフェースを使用して、名前付きおよび匿名の一時オブジェクト型(属性付きで構造化されたもの)とコレクション型を作成できます。

OCITypeBeginCreate()コールを使用して、一時オブジェクト型とコレクション型の作成を開始します(作成する型は、型コード・パラメータによって決定されます)。

OCIDescriptorAlloc()を使用して、パラメータ・ハンドルを割り当てる必要があります。次に、OCIAttrSet()を使用して、型情報(オブジェクト型の属性とコレクション要素の型に関する情報)を設定する必要があります。オブジェクト型の場合は、例12-10に示すように、OCITypeAddAttr()を使用して属性情報をその型に追加します。最新の属性情報が追加された後で、OCITypeEndCreate()をコールする必要があります。

コレクション型の場合は、例12-11に示すように、OCITypeSetCollection()を使用して情報をコレクション要素型に設定します。次に、OCITypeEndCreate()をコールして、作成を終了します。

OCIDescribeAny()コールを使用すると、永続型に対応するOCITypeを取得できます。

例12-10 型インタフェースを使用したオブジェクト型の作成

OCITypeBeginCreate( ...)        /* Begin Type Creation */
OCIDescriptorAlloc(...)
OCIAttrSet(...)
OCITypeAddAttr(...)             /* Add attribute 1 */
OCIAttrSet(...)
OCITypeAddAttr(...)             /* Add attribute 2 */
...
OCITypeEndCreate(...)           /* End Type Creation */

例12-11 型インタフェースを使用したコレクション型の作成

OCITypeBeginCreate( ...)        /* Begin Type Creation */
OCIDescriptorAlloc(...)
OCIAttrSet(...)
OCITypeSetCollection(...)       /* Set information on collection element */
OCITypeEndCreate(...)           /* End Type Creation */

OCITypeコールのパラメータ記述子の作成について

OCIDescriptorAlloc()コールを使用すると、OCIParam (親ハンドルが環境ハンドルの場合)を割り当てることができます。その後、次の使用可能な属性の型を使用して、OCIAttrSet()をコールし、関連する型情報を設定できます。

  • OCI_ATTR_PRECISION

数値精度を設定します。(ub1 *)属性値を、精度値を保持しているバッファに渡します。

  • OCI_ATTR_SCALE

数値のスケールを設定します。(sb1 *)属性値を、スケール値を保持しているバッファに渡します。

  • OCI_ATTR_CHARSET_ID

キャラクタ・タイプのキャラクタ・セットIDを設定します。(ub2 *)属性値を、キャラクタ・セットIDを保持しているバッファに渡します。

  • OCI_ATTR_CHARSET_FORM

キャラクタ・タイプのキャラクタ・セット・フォームを設定します。(ub1 *)属性値を、キャラクタ・セット・フォーム値を保持しているバッファに渡します。

  • OCI_ATTR_DATA_SIZE

VARCHAR2RAWなどの長さ。(ub2 *)属性値を、長さを保持しているバッファに渡します。

  • OCI_ATTR_TYPECODE

型コードを設定します。(ub2 *)属性値を、型コードを保持しているバッファに渡します。この属性は、最初に設定する必要があります。

  • OCI_ATTR_TDO

オブジェクトまたはコレクション属性のOCITypeを設定します。(OCIType *)属性値を、その属性に対応するOCITypeに渡します。AnyTypeの構成中に、このOCIParamを使用する場合、OCITypeが確保されていることを確認します。一時型属性の場合の割当て時間は、少なくともトップレベルのOCITypeが作成されている時間内である必要があります。それ以外の場合は例外が戻されます。

  • 組込み型の場合、SQL型属性にアクセス可能な型コード(OCI_ATTR_TYPECODEに対する許容値)は、次のとおりです。

    OCI_TYPECODE_DATEOCI_TYPECODE_NUMBER

    OCI_TYPECODE_VARCHAROCI_TYPECODE_RAW

    OCI_TYPECODE_CHAROCI_TYPECODE_VARCHAR2

    OCI_TYPECODE_VARCHAROCI_TYPECODE_BLOB

    OCI_TYPECODE_BFILEOCI_TYPECODE_CLOB

    OCI_TYPECODE_TIMESTAMPOCI_TYPECODE_TIMESTAMP_TZ

    OCI_TYPECODE_TIMESTAMP_LTZ

    OCI_TYPECODE_INTERVAL_YMおよびOCI_TYPECODE_INTERVAL_DS

  • 属性またはコレクション要素の型自体が別の一時型である場合は、OCI_ATTR_TYPECODEOCI_TYPECODE_OBJECTOCI_TYPECODE_REF (REF用)、OCI_TYPECODE_VARRAYまたはOCI_TYPECODE_TABLEに設定し、OCI_ATTR_TDOを一時型に対応するOCITypeに設定します。

  • ユーザー定義の型属性の場合、OCI_ATTR_TYPECODEに対する許容値は、次のとおりです。

    • OCI_TYPECODE_OBJECT (オブジェクト型用)

    • OCI_TYPECODE_REF (REF型用)

    • OCI_TYPECODE_VARRAYまたはOCI_TYPECODE_TABLE (コレクション用)

    ユーザー定義の場合は、OCI_ATTR_TDOを適切なユーザー定義型のOCITypeに設定する必要があります。

永続型のOCITypeの取得について

次の例のように、OCIDescribeAny()コールを使用すると、永続型に対応するOCITypeを取得できます。

OCIDescribeAny(svchp, errhp. (void  *)"HR.EMPLOYEES",
               (ub4)strlen("HR.EMPLOYEES"),
               (ub1)OCI_OTYPE_NAME, (ub1)OCI_DEFAULT, OCI_PTYPE_TYPE, dschp);

記述ハンドル(dschp)から、OCIAttrGet()コールを使用して、OCITypeを取得できます。

型のアクセス・コール

一時型の記述を使用してOCIDescribeAny()をコールし、その型の動的記述にアクセスできます。OCITypeのポインタはobjtypeOCI_OTYPE_PTRに設定されている場合、OCIDescribeAny()に直接渡すことができます。これによって、属性情報を名前および位置で取得できます。

OCIDescribeAny()への拡張

一時型が組込み型である(組込みの型コードで作成されている)場合、この一時型(OCI_PTYPE_TYPE型に相当)を記述するパラメータ・ハンドルでは、次の追加の属性がサポートされます。

  • OCI_ATTR_DATA_SIZE

  • OCI_ATTR_TYPECODE

  • OCI_ATTR_DATA_TYPE

  • OCI_ATTR_PRECISION

  • OCI_ATTR_SCALE

  • OCI_ATTR_CHARSET_ID

  • OCI_ATTR_CHARSET_FORM

  • OCI_ATTR_LFPRECISION

  • OCI_ATTR_FSPRECISION

これらの属性には、型属性の記述時に通常付与される内容が含まれています。

注意:

これらの属性は、一時的な組込み型に対してのみサポートされます。属性OCI_ATTR_IS_TRANSIENT_TYPEOCI_ATTR_IS_PREDEFINED_TYPEは、これらの型に該当します。永続型の場合、これらの属性は、その型の属性(OCI_PTYPE_TYPE_ATTR型に相当)のパラメータ・ハンドルでのみサポートされます。

OCIAnyDataインタフェースについて

OCIAnyDataは、型情報とその型のデータ・インスタンス(つまり、自己記述データ)をカプセル化します。OCIAnyDataは、OCIAnyDataConvert()コールを使用して、組込み型またはユーザー定義型のインスタンスから作成できます。このコールがOCIAnyDataへの変換(キャスト)を実行します。

また、オブジェクト型およびコレクション型は、型情報(OCIType)を指定してOCIAnyDataBeginCreate()をコールすることにより、ピースごと(オブジェクト型に対して一度に1つの属性または一度に1つのコレクション要素)に構成できます。その後、オブジェクト型に対してOCIAnyDataAttrSet()、コレクション型に対してOCIAnyDataCollAddElem()を使用できます。最後に、OCIAnyDataEndCreate()コールを使用して、作成プロセスを終了します。

その後で、アクセス・ルーチンを起動できます。OCIAnyDataを対応する型のインスタンスに変換(キャスト)するには、OCIAnyDataAccess()を使用します。

オブジェクト型またはコレクション型に基づいたOCIAnyDataも個別にアクセスできます。

パフォーマンス改善のために、特別なコレクション構成とアクセス・コールが用意されています。例12-12に示すように、これらのコールを使用すると、メモリー内での不要なコレクションの作成やコレクション全体のコピーなどが回避できます。

または

OCIAnyDataCollAddElem(...)    /* Element-wise construction for collections */

OCIAnyDataEndCreate(...)      /* End OCIAnyData Creation */

例12-12 パフォーマンス改善のための特別な構成とアクセス・コールの使用

OCIAnyDataConvert(...)        /* Cast a built-in or user-defined type instance
                                 to an OCIAnyData in 1 call. */

OCIAnyDataBeginCreate(...)    /* Begin AnyData Creation */

OCIAnyDataAttrSet(...)        /* Attribute-wise construction for object types */

OCIAnyData関数のNCHAR型コード

OCIAnyDataTypeCodeToSqlt()関数は、OCIAnyData値のOCITypeCodeを、OCIAnyData APIが戻す値の表現に対応するSQLTコードに変換します。

次の型コードは、OCIAnyData関数でのみ使用されます。

  • OCI_TYPECODE_NCHAR

  • OCI_TYPECODE_NVARCHAR2

  • OCI_TYPECODE_NCLOB

OCIDescribeAny()などその他の関数のコールでは、これらの型コードは戻されず、キャラクタ・セット・フォームを使用してデータがNCHARかどうか(キャラクタ・セット・フォームがSQLCS_NCHARかどうか)を判断する必要があります。

OCIAnyDataTypeCodeToSqlt()は、OCI_TYPECODE_CHARおよびOCI_TYPECODE_VARCHAR2を、キャラクタ・セット・フォームがSQLCS_IMPLICITの出力値SQLT_VST (OCIStringマッピングに対応)に変換します。また、OCI_TYPECODE_NVARCHAR2は、キャラクタ・セット・フォームがSQLCS_NCHARSQLT_VST (OCIStringマッピングはOCIAnyData APIで使用されます)を戻します。

OCIAnyDataSetインタフェースについて

OCIAnyDataSetは、型情報とその型のインスタンスの集合をカプセル化します。構成処理を開始するには、OCIAnyDataSetBeginCreate()をコールします。

OCIAnyDataSetAddInstance()をコールして新規インスタンスを追加すると、このコールは、そのインスタンスに対応するOCIAnyDataを戻します。

次に、このインスタンスを作成するためのOCIAnyData関数を呼び出すことができます。すべてのインスタンスが追加されたら、OCIAnyDataSetEndCreate()をコールします。

アクセスする場合は、OCIAnyDataSetGetInstance()をコールして、そのインスタンスに対応するOCIAnyDataを取得します。順次アクセスのみがサポートされます。その後で、次の例に示すように、OCIAnyDataアクセス関数を起動できます。

OCIAnyDataSetBeginCreate(...)   /* Begin AnyDataSet Creation */
OCIAnyDataSetAddInstance(...)   /* Add a new instance to the AnyDataSet */
                                /* Use the OCIAnyData*() functions to create
                                   the instance */
OCIAnyDataSetEndCreate(...)     /* End OCIAnyDataSet Creation */

関連項目:

名前付きデータ型のバインドについて

この項では、オブジェクトやコレクションなどの名前付きデータ型とREFのバインドについて説明します。

名前付きデータ型のバインド

名前付きデータ型(オブジェクト型やコレクション)のバインドでは、OCIBindByName()またはOCIBindByName2()、あるいはOCIBindByPos()またはOCIBindByPos2()の後にもう1つのバインド・コールが必要です。

OCIBindObject()コールで、オブジェクト型のバインド固有の追加属性を設定します。OCIアプリケーションでは、このコールを使用して、オブジェクト・データ型の列を持つ表からデータをフェッチします。

OCIBindObject()コールでパラメータの1つとして、名前付きデータ型の型記述子オブジェクト(TDO)を受け取ります。データ型OCITypeのTDOは、名前付きデータ型が作成されるときに作成され、データベースに格納されます。これには、型とその属性についての情報が入っています。アプリケーションでは、OCITypeByName()をコールしてTDOを取得できます。

OCIBindObject()コールでは、名前付きデータ型バインド用の標識変数または構造体も設定します。

名前付きデータ型をバインドするときは、SQLT_NTYデータ型定数を使用して、バインドするプログラム変数のデータ型を指定します。SQLT_NTYは、名前付きデータ型を表現するC構造体をバインドすることを示します。この構造体へのポインタをバインド・コールに渡します。

スーパータイプがある場合は、継承とインスタンスの代入性を使用して、サブタイプのインスタンスをバインドできます。

場合によっては、名前付きデータ型の操作に3つのバインド・コールが必要になることがあります。たとえば、名前付きデータ型の静的配列をPL/SQL表にバインドするには、OCIBindByName()またはOCIBindByName2()OCIBindArrayOfStruct()およびOCIBindObject()という3つのコールを呼び出します。

関連項目:

REFのバインドについて

名前付きデータ型と同様に、REFのバインドも2ステップで処理します。

最初にOCIBindByName()またはOCIBindByName2()、あるいはOCIBindByPos()またはOCIBindByPos2()をコールし、次にOCIBindObject()をコールします。

REFは、SQLT_REFデータ型を使用してバインドします。SQLT_REFを使用する場合、バインドするプログラム変数は、OCIRef *型の変数にする必要があります。

スーパータイプへのREFがある場合は、継承とREFの代入性を使用して、REFの値をサブタイプのインスタンスにバインドできます。

関連項目:

名前付きデータ型およびREFバインドの情報

名前付きデータ型およびREFバインドを取り扱う場合は、次に示す重要な情報について注意してください。メモリー割当てと標識変数の使用方法についての参照先も示します。

  • バインド対象のデータ型がSQLT_NTYである場合は、OCIBindObject()コールのインジケータ構造体パラメータ(void ** indpp)が使用され、スカラー・インジケータは完全に無視されます。

  • データ型がSQLT_REFの場合は、スカラー・インジケータが使用され、OCIBindObject()のインジケータ構造体のパラメータは完全に無視されます。

  • インジケータ構造体の使用はオプションです。ユーザーは、indppパラメータのNULLポインタをOCIBindObject()コールに渡すことができます。そのため、バインド時に、オブジェクトがアトミックNULLではなく、そのオブジェクトのどの属性もNULLではありません。

  • OCIBindObject()コールのインジケータ構造体サイズ・ポインタindspおよびプログラム変数サイズ・ポインタpgvspは、オプションです。これらのパラメータが不要な場合、ユーザーはNULLを渡すことができます。

配列バインドに関する情報

配列挿入または配列フェッチ用に、名前付きデータ型またはREFの配列バインドを行うには、ユーザーはポインタの配列を適切な型のバッファ(事前割当て済またはそれ以外)に渡す必要があります。

同様に、スカラー・インジケータの配列(SQLT_REF型)またはポインタ配列を、インジケータ構造体(SQLT_NTY型)に渡す必要があります。

関連項目:

SQLT_NTYの詳細は、「名前付きデータ型: オブジェクト、VARRAY、ネストした表」を参照してください

名前付きデータ型の定義について

この項では、名前付きデータ型(オブジェクト、コレクションなど)とREFの定義について説明します。

名前付きデータ型出力変数の定義について

名前付きデータ型(オブジェクト型、NESTED TABLE、VARRAY)の定義には、2つの定義コールが必要です。

最初にdtyパラメータにSQLT_NTYを指定して、OCIDefineByPos()またはOCIDefineByPos2()をコールします。アプリケーションでは、OCIDefineByPos()またはOCIDefineByPos2()に続いて、OCIDefineObject()をコールして、名前付きデータ型定義に関係するその他の属性を設定する必要があります。この場合、OCIDefineByPos()またはOCIDefineByPos2()内のデータ・バッファ・ポインタは無視されます。

名前付きデータ型定義のSQLT_NTYデータ型定数を指定します。この場合、結果のデータが名前付きデータ型のホスト言語表現の中にフェッチされます。通常、これはObject Type Translatorによって生成されるC構造体になります。

OCIDefineObject()コールを行うときは、C構造体のアドレスへのポインタ(事前割当て済またはそれ以外)を定義する必要があります。オブジェクトは、OCIObjectNew()を使用して作成され、キャッシュまたはユーザー定義のメモリーに割り当てられます。

ただし、継承が行われる場合は、オブジェクト・キャッシュ内のオブジェクトを使用し、ユーザー・メモリーから割り当てられたオブジェクトをスタックから渡さないことを強くお薦めします。そうしない場合、インスタンスの代入性により、クライアントがスーパータイプ・インスタンスを予期しているにもかかわらず、サーバーがサブタイプ・インスタンスを戻してしまうことがあります。サーバーは、オブジェクトを動的にサイズ変更する必要があります。この操作は、キャッシュ内のオブジェクトに対してのみ可能です。

関連項目:

REF出力変数の定義について

名前付きデータ型と同様に、REF出力変数の定義も2ステップで処理します。

第1ステップでOCIDefineByPos()またはOCIDefineByPos2()をコールし、第2ステップでOCIDefineObject()をコールします。また、名前付きデータ型の場合と同様に、OCIDefineByPos()dtyパラメータにSQLT_REFデータ型定数を渡します。

SQLT_REFでは、アプリケーションで結果として得るデータをOCIRef *型変数にフェッチすることを示します。このREFをオブジェクトの確保とナビゲーションの一部として使用します。

関連項目:

名前付きデータ型、REF定義およびPL/SQL OUTバインドの情報

名前付きデータ型およびREF定義を取り扱う場合は、次に示す重要な情報について注意してください。メモリー割当てと標識変数の使用方法についての参照先も示します。

PL/SQL OUTバインドとは、プレースホルダをPL/SQLブロックの出力変数にバインドすることです。SQL文では出力バッファを定義コールで設定しますが、PL/SQLブロックでは出力バッファをバインド・コールで設定します。

  • 定義対象のデータ型がSQLT_NTYの場合は、OCIDefineObject()コールのインジケータ構造体パラメータ(void ** indpp)が使用され、スカラー・インジケータは完全に無視されます。

  • データ型がSQLT_REFの場合は、スカラー・インジケータが使用され、OCIDefineObject()のインジケータ構造体のパラメータは完全に無視されます。

  • インジケータ構造体の使用はオプションです。ユーザーは、indppパラメータのNULLポインタをOCIDefineObject()コールに渡すことができます。そのため、フェッチまたはPL/SQL OUTバインド時に、NULLであるかどうかの情報はユーザーには認識されません。

  • SQL定義またはPL/SQL OUTバインドの場合、プログラマは出力変数またはインジケータのいずれかに対して事前割当済メモリーを渡すことができます。渡されると、その事前割当て済メモリーが結果データの格納に使用され、2次メモリー(アウト・ライン・メモリー)がある場合は、その内容がすべて割当て解除されます。事前割当て済メモリーは、キャッシュ(OCIObjectNew()コールの結果)から取得する必要があります。

    注意:

    キャッシュからではなく、クライアント・アプリケーションで所有するメモリー領域からメモリーを割り当てる場合は、オブジェクトにアウト・ライン2次メモリーがないことを確認する必要があります。

SQLT_NTY型を使用したオブジェクト定義に対してオブジェクト・メモリーを事前割当てするには、クライアント・アプリケーションでOCIObjectNew()関数を使用する必要があります。クライアント・アプリケーションでは、malloc()を使用する割当てや、スタックへの割当てなど、独自のプライベート・メモリー領域へのオブジェクトの割当ては行わないでください。OCIObjectNew()関数によって、オブジェクト・キャッシュにオブジェクトが割り当てられます。割り当てられたオブジェクトは、OCIObjectFree()を使用すると解放できます。

注意:

ユーザーがオブジェクト・メモリーを事前割当てせずに、出力変数をNULLポインタ値に初期化した場合でも、OCIDefineObject()の動作に変化はありません。この場合、オブジェクトはOCIライブラリによって暗黙的にオブジェクト・キャッシュ内に割り当てられます。

  • SQL定義またはPL/SQL OUTバインドの場合、ユーザーが出力変数またはインジケータに対してNULLアドレスを渡すと、その変数またはインジケータ用のメモリーは、OCIによって暗黙的に割り当てられます。

  • SQLT_NTY型の出力オブジェクトが(SQL定義またはPL/SQL OUTバインドで)アトミックNULLの場合は、NULLインジケータ構造体のみが(必要であれば暗黙的に)割り当てられてデータが挿入され、オブジェクトがアトミックNULLであることが明示されます。トップレベルのオブジェクトは、暗黙的に割り当てられません。

  • アプリケーションでは、OCIObjectFree()をコールしてインジケータを解放できます。トップレベルのオブジェクトがある場合は(アトミックNULLでないオブジェクトの場合など)、そのトップレベルのオブジェクトをOCIObjectFree()で解放すると、インジケータも解放されます。オブジェクトがアトミックNULLである場合は、トップレベルのオブジェクトがないので、インジケータを個別に解放する必要があります。

  • OCIDefineObject()コールのインジケータ構造体サイズ・ポインタindszpおよびプログラム変数サイズ・ポインタpvszspは、オプションです。これらのパラメータが不要な場合、ユーザーはNULLを渡すことができます。

この項には次のトピックが含まれます。「配列定義に関する情報」

関連項目:

配列定義に関する情報

名前付きデータ型またはREFの配列定義を行うには、ユーザーはポインタ配列を適切な型のバッファ(事前割当て済またはそれ以外)に渡す必要があります。同様に、スカラー・インジケータの配列(SQLT_REF型)またはポインタ配列を、インジケータ構造体(SQLT_NTY型)に渡す必要があります。

Oracle Cデータ型のバインドおよび定義について

この項では、Oracle C名前付きデータ型のバインドと定義に関する情報をまとめています

これまでの章では、OCIのバインド操作と定義操作について説明しました。「OCIのプレースホルダのバインドについて」では、OCIバインド操作の基本について、「OCIでの出力変数の定義について」では、OCI定義操作の基本について説明しています。名前付きデータ型およびREFのバインドと定義の詳細は、「OCIでのバインドおよび定義」を参照してください。

バインドと定義の基本的な機能に関する章では、アプリケーションでSQL文の入力(バインド)値として、または問合せに対する出力(定義)バッファとしてスカラー変数またはスカラーの配列を使用する方法を示しています。

名前付きデータ型とREFに関する項では、オブジェクトや参照をバインドまたは定義する方法を説明しています。「オブジェクトの確保」では、さらにオブジェクト参照の確保について、「埋込みオブジェクトのフェッチ」では、埋込みインスタンスのフェッチについて、「オブジェクト・ナビゲーション」では、オブジェクト・ナビゲーションについて説明しています。

この項では、この章で説明するデータ型マッピングに従って、個々の属性値のバインドと定義の方法を説明します。

この章で定義する型の1つであるOCINumberOCIStringなどの変数は、一般にアプリケーションで宣言でき、適切なデータ型コードが指定されているため、OCIバインドまたは定義操作で直接使用できます。表12-12は、Cマッピングとともにバインドおよび定義で使用できるデータ型と、バインドまたは定義コールのdty (データ型コード)パラメータで指定する必要のある、OCI外部データ型のリストです。

表12-12 バインドおよび定義用のデータ型マッピング

データ型 Cマッピング OCIの外部データ型とコード

Oracle NUMBER

OCINumber

VARNUM(SQLT_VNU)

Oracle DATE

OCIDate

SQLT_ODT

BLOB

OCILobLocator *

SQLT_BLOB

CLOBNCLOB

CILobLocator *

SQLTY_LOB

VARCHAR2NVARCHAR2

OCIString *

SQLT_VST脚注 1

RAW

OCIRaw *

SQLT_LVB脚注 1

CHARNCHAR

OCIString *

SQLT_VST

オブジェクト

struct *

名前付きデータ型(SQLT_NTY)

REF

OCIRef *

REF(SQLT_REF)

VARRAY

OCIArray *

名前付きデータ型(SQLT_NTY)

NESTED TABLE

OCITable *

名前付きデータ型(SQLT_NTY)

DATETIME

OCIDateTime *

詳細は、「日時および時間隔(OCIDateTime、OCIInterval)」を参照してください。

INTERVAL

OCIInterval *

詳細は、「日時および時間隔(OCIDateTime、OCIInterval)」を参照してください。

脚注 1

OCIString *型の定義変数にデータをフェッチするには、最初にOCIStringResize()ルーチンを使用して文字列のサイズを設定する必要があります。そのためには、記述操作によって選択リスト・データの長さを取得することが必要な場合があります。同様に、OCIRaw *も最初にOCIStringResize()でサイズを決定する必要があります。

次の項では、Cにマッピングしたデータ型のOCIアプリケーションでの使用例を示します。

関連項目:

バインドおよび定義の例

OCIのバインド操作と定義操作でOCINumber型の変数を使用する方法を示します

この項では、OCIのバインド操作と定義操作でOCINumber型の変数を使用する例を示します。

この例では、次のようなpersonというオブジェクト型が作成されていると仮定します。

CREATE TYPE person AS OBJECT
(name     varchar2(30),
salary     number);

この型を使用して、person型の列を持つemployees (従業員)表を作成します。

CREATE TABLE employees
(emp_id    number,
job_title  varchar2(30),
emp        person);

Object Type Translator (OTT)では、personに対して次のC構造体とNULLインジケータ構造体が生成されます。

struct person
{   OCIString * name;
   OCINumber salary;};
typedef struct person person;

struct person_ind
{   OCIInd  _atomic;
   OCIInd  name;
   OCIInd  salary;}
typedef struct person_ind person_ind;

employees表は値が入り、OCIアプリケーションはpersonの変数を宣言するとします。

person *my_person;

また、アプリケーションでは、次のように、SELECT文によってオブジェクトがその変数にフェッチされたとします。

text *mystmt = (text *) "SELECT person FROM employees
                        WHERE emp.name='Andrea'";

この場合、「OCIでの拡張定義操作」の説明に従って、名前付きデータ型の適切なOCI定義コールを使用し、my_personをこの文の出力変数として定義する必要があります。文を実行すると、Andreaという名前のpersonオブジェクトがmy_person変数に取り出されます。

オブジェクトがmy_personに取り出されると、OCIアプリケーションでmy_personの名前や給与などの属性にアクセスできるようになります。

アプリケーションでは、別の従業員の給与を、次の例ようにAndreaと同様に更新します。

text *updstmt = (text *) "UPDATE employees SET emp.salary = :newsal 
                            WHERE emp.name = 'MONGO'";

my_person->salaryに格納されているAndreaの給与は、プレースホルダ:newsalにバインドされ、VARNUMの外部データ型(データ型コード=6)をバインド操作に指定します。

OCIBindByName(...,":newsal",...,&my_person->salary,...,6,...);
OCIStmtExecute(...,updstmt,...);

文を実行すると、データベースにあるMongoの給与が、my_personに格納されているように、Andreaの給与と等しくなります。

その反対に、Mongoの給与をデータベースに問い合せてから給与に必要な割当てを行うことにより、アプリケーションでAndreaの給与をMongoの給与と同額になるよう更新できます。

text *selstmt = (text *) "SELECT emp.salary FROM employees 
                           WHERE emp.name = 'MONGO'";
OCINumber mongo_sal;
...
OCIDefineByPos(...,1,...,&mongo_sal,...,6,...);
OCIStmtExecute(...,selstmt,...);
OCINumberAssign(...,&mongo_sal, &my_person->salary);

この場合には、アプリケーションでOCINumberの型の出力変数を宣言し、それを定義のステップで使用します。アプリケーションでは、位置1の出力変数も定義し、適切なデータ型コード(VARNUMの場合は6)を使用します。

mongo_salというOCINumberに給与の値をフェッチし、適切なOCI関数OCINumberAssign()を使用して、現在キャッシュ内にあるAndreaオブジェクトのコピーに新しい給与を割り当てます。データベース内にあるデータを変更するには、変更内容をサーバーにフラッシュする必要があります。

関連項目:

給与更新の例

特定のOCI作業を実行するための、コールのフローの使用方法を示します。

前の項の例では、Oracleデータ型がバインド操作と定義操作に与える柔軟性に関して説明しました。この項では、同じ操作を異なる方法でどのように実行するかを説明します。これらのデータ型は、OCIアプリケーション内で様々な方法で使用できます。

この項の例は、特定のOCI作業を実行するのに使用されるコールのフローを説明します。これらの例では拡張擬似コードを使用しています。実際の関数名を使用していますが、簡素化のためにパラメータとタイプキャストは一部のみ示します。ハンドルの割当てなど、その他の必要なOCIコールも省略しています。

シナリオ

これから示す例のシナリオは、次のとおりです。

  • ある病院のemployees表に、BRUCEという従業員が存在します。前の項のperson型およびemployees表の作成文を参照してください。

  • Bruceの現在の職種は、RADIOLOGISTです。

  • Bruceは、RADIOLOGY_CHIEFに昇進したため、それに伴った昇給があります。

  • 次に示すように、病院の給与はドル単位の整数値とし、職種に応じて設定し、salariesという表に格納します。

    CREATE TABLE salaries
    (job_title   varchar2(20),
    salary       integer));
    
  • Bruceの給与を昇進にあわせて更新します。

Bruceの給与を更新して昇進を反映するには、アプリケーションでは、salaries表からRADIOLOGY_CHIEFに該当する給与を取り出して、Bruceの給与を更新する必要があります。別のステップで、彼の新しい職種と変更済オブジェクトをデータベースに書き込みます。

次のようにperson型の変数を宣言したとします。

person * my_person;

Bruceに対応するオブジェクトはpersonにフェッチされます。給与更新を実行するには、次の各項に示す3通りの方法があります。

方法1 - フェッチ、変換、割当て

例12-13では次の方法をとります。

  1. 整変数を使用して従来のOCI定義を行い、データベースから新しい給与を取り出します。
  2. 整数をOCINumberに変換します。
  3. 新しい給与をBruceに割り当てます。

例12-13 給与更新の方法1: フェッチ、変換、割当て

#define INT_TYPE 3        /* data type code for sword integer define */

text *getsal = (text *) "SELECT salary FROM salaries
                        WHERE job_title='RADIOLOGY_CHIEF'";
sword    new_sal;
OCINumber   orl_new_sal;
...
OCIDefineByPos(...,1,...,new_sal,...,INT_TYPE,...);
                        /* define int output */
OCIStmtExecute(...,getsal,...);
                        /* get new salary as int */
OCINumberFromInt(...,new_sal,...,&orl_new_sal);
                        /* convert salary to OCINumber */
OCINumberAssign(...,&orl_new_sal, &my_person->salary);
                        /* assign new salary */

方法2 - フェッチ、割当て

この方法(例12-14)では、方法1で説明したステップを1つ省略します。

  1. OCINumber型の出力変数を定義します。そのため値を取り出した後の変換は必要ありません。
  2. 新しい給与をBruceに割り当てます。

例12-14 給与更新の方法2: フェッチ、割当て、変換なし

#define VARNUM_TYPE 6         /* data type code for defining VARNUM */

text *getsal = (text *) "SELECT salary FROM salaries
                              WHERE job_title='RADIOLOGY_CHIEF'";
OCINumber   orl_new_sal;
...
OCIDefineByPos(...,1,...,orl_new_sal,...,VARNUM_TYPE,...);
                                     /* define OCINumber output */
OCIStmtExecute(...,getsal,...);      /* get new salary as OCINumber */
OCINumberAssign(...,&orl_new_sal, &my_person->salary); 
                                     /* assign new salary */

方法3 - 直接フェッチ

この方法(例12-15)では、操作全体を1回の定義とフェッチで実行します。出力変数を介在させる必要はなく、データベースから取り出した値を、キャッシュに格納されているオブジェクトの給与属性に直接フェッチします。

Bruceに対応するオブジェクトはオブジェクト・キャッシュ内に確保されているため、その給与属性の位置を定義変数として使用し、その変数に直接実行し、フェッチを行います。

例12-15 給与更新の方法3: 直接フェッチ

#define VARNUM_TYPE 6         /* data type code for defining VARNUM */

text *getsal = (text *) "SELECT salary FROM salaries
                            WHERE job_title='RADIOLOGY_CHIEF'";
...
OCIDefineByPos(...,1,...,&my_person->salary,...,VARNUM_TYPE,...);
            /* define bruce's salary in cache as output variable */
OCIStmtExecute(...,getsal,...);
             /* execute and fetch directly */

まとめと注意

この3つの例に示したように、Cデータ型を使用すると柔軟性のあるバインドと定義を実行できます。たとえば、整数をフェッチし、OCINumberに変換して操作できます。この方法では、OCINumberを中間的な変数として使用し、問合せの結果を格納できます。あるいは、目的のオブジェクトのOCINumber属性にデータを直接フェッチすることもできます。

注意:

OCIのこれらの例では、問合せの実行前に出力変数が定義されている場合、結果として得られるデータは、出力バッファに直接プリフェッチされることを覚えておいてください。

これらの例では、アプリケーションで変更がデータベースに確実に永続的に書き込まれるためには、追加ステップが必要です。この追加ステップには、SQLのUPDATEコールとOCIトランザクションのコミット・コールを含めることができます。

これらの例ではすべて定義操作を処理していますが、同じような状況がバインドにも当てはまります。

同様に、これらの例ではOCINumber型のみを扱いましたが、この章でこれから説明する他のOracleのC型についても、同じような種々の操作を実行できます。

SQLT_NTYのバインドおよび定義の例

次のコード・フラグメントは、OCIBindObject()などのバインド・コールでのSQLT_NTY名前付きデータ型、およびOCIDefineObject()などの定義コールでのSQLT_NTY名前付きデータ型の使用方法を示しています。

それぞれの例で、前に定義したSQL文を処理します。

この項には次のトピックが含まれます:

SQLT_NTYのバインドの例

例12-16は、OCIBindObject()などのバインド・コールでのSQLT_NTY名前付きデータ型の使用方法を示しています。

例12-16 OCIBindObject()などのSQLT_NTYバインド・コールの使用

/*
** This example performs a SQL insert statement
*/
void insert(envhp, svchp, stmthp, errhp, insstmt, nrows)
OCIEnv *envhp;
OCISvcCtx *svchp;
OCIStmt *stmthp;
OCIError *errhp;
text *insstmt;
ub2   nrows;
{
  OCIType *addr_tdo = (OCIType *)0 ;
  address  addrs;
  null_address naddrs;
  address *addr = &addrs;
  null_address *naddr = &naddrs;
  sword custno =300;
  OCIBind *bnd1p, *bnd2p;
  ub2 i;

  /* define the application request  */
  checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insstmt,
           (ub4) strlen((char *)insstmt),
           (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));

  /* bind the input variable */
 checkerr(errhp, OCIBindByName(stmthp, &bnd1p, errhp, (text *) ":custno",
          (sb4) -1, (void  *) &custno,
          (sb4) sizeof(sword), SQLT_INT,
          (void  *) 0, (ub2 *)0, (ub2 *)0, (ub4) 0, (ub4 *) 0,
          (ub4) OCI_DEFAULT));

  checkerr(errhp, OCIBindByName(stmthp, &bnd2p, errhp, (text *) ":addr",
          (sb4) -1, (void  *) 0,
          (sb4) 0, SQLT_NTY, (void  *) 0, (ub2 *)0, (ub2 *)0,
          (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT));

  checkerr(errhp,
                OCITypeByName(envhp, errhp, svchp, (const text *)
                SCHEMA, (ub4) strlen((char *)SCHEMA),
                (const text *)"ADDRESS_VALUE",
                (ub4) strlen((char *)"ADDRESS_VALUE"),
                (text *)0, 0, OCI_DURATION_SESSION,
                OCI_TYPEGET_HEADER, &addr_tdo));

  if(!addr_tdo)
  {
    printf("Null tdo returned\n");
    return;
  }

  checkerr(errhp, OCIBindObject(bnd2p, errhp, addr_tdo, (void  **) &addr,
        (ub4 *) 0, (void  **) &naddr, (ub4 *) 0));

SQLT_NTYの定義の例

例12-17は、OCIDefineObject()などの定義コールでのSQLT_NTY名前付きデータ型の使用方法を示しています。

例12-17 OCIDefineObject()などのSQLT_NTY定義コールの使用

/*
** This example executes a SELECT statement from a table that includes
** an object.
*/

void selectval(envhp, svchp, stmthp, errhp)
OCIEnv *envhp;
OCISvcCtx *svchp;
OCIStmt *stmthp;
OCIError *errhp;
{
  OCIType *addr_tdo = (OCIType *)0;
  OCIDefine *defn1p, *defn2p;
  address *addr = (address *)NULL;
  sword custno =0;
  sb4 status;

  /* define the application request  */
  checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selvalstmt,
                        (ub4) strlen((char *)selvalstmt),
                        (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));

  /* define the output variable */
checkerr(errhp, OCIDefineByPos(stmthp, &defn1p, errhp, (ub4) 1, (void  *)
       &custno, (sb4) sizeof(sword), SQLT_INT, (void  *) 0, (ub2 *)0,
       (ub2 *)0, (ub4) OCI_DEFAULT));

checkerr(errhp, OCIDefineByPos(stmthp, &defn2p, errhp, (ub4) 2, (void  *)
        0, (sb4) 0, SQLT_NTY, (void  *) 0, (ub2 *)0,
        (ub2 *)0, (ub4) OCI_DEFAULT));

checkerr(errhp,
               OCITypeByName(envhp, errhp, svchp, (const text *)
               SCHEMA, (ub4) strlen((char *)SCHEMA),
               (const text *) "ADDRESS_VALUE",
               (ub4) strlen((char *)"ADDRESS_VALUE"),
               (text *)0, 0, OCI_DURATION_SESSION,
               OCI_TYPEGET_HEADER, &addr_tdo));

  if(!addr_tdo)
  {
    printf("NULL tdo returned\n");
    return;
  }


  checkerr(errhp, OCIDefineObject(defn2p, errhp, addr_tdo, (void  **)
       &addr, (ub4 *) 0, (void  **) 0, (ub4 *) 0));

  checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
       (OCISnapshot *) NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT));