23 OCIでのJSONのサポート

SQL型JSONのサポートは、JSONデータ用に設計されています。Oracle DatabaseではJSONデータにJSON型を使用することをお薦めします。

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

23.1 JSONデータ型のサポート

Oracle Databaseリリース21c以降では、SQL型JSONのサポートは、特にJSONデータ用に設計されています。Oracle DatabaseではJSONデータにJSON型を使用することをお薦めします。これにはバイナリ形式OSONが使用されます。これは、Oracle DatabaseサーバーとOracle Databaseクライアントの両方で問合せおよび更新を迅速に行うための、Oracle用に最適化されたバイナリJSON形式です。JSONデータ型を使用するには、compatibleデータベース初期化パラメータに20以上を設定する必要があります。

JSONデータがSQLデータ型JSONの場合、Oracleでは標準のJSON言語のスカラー型(数値、文字列、ブール、nullなど)のセットが拡張され、SQLスカラー型に対応するスカラーが含まれています(binary、date、timestamp、year-month interval、day-second interval、double、floatなど)。これにより、JSON言語が拡張され、JSON言語とSQLの間でスカラー・データの変換がより簡単になり、データの損失がなくなります。

23.1.1 JSONのOCI表現

この項では、JSONのOCI表現について説明します。

標準JSONは、言語または表記法として、オブジェクト、配列、数値、文字列、ブール、nullなどのデータ型が事前定義されています。オブジェクトと配列を除くすべてのJSON言語型はスカラー型です。

OCIJson記述子は、OCIのJSONドキュメントを表すために使用されます。これは記述子タイプOCI_DTYPE_JSONで識別されます。この記述子は、OCIDescriptorAlloc()関数およびOCIDescriptorFree ()関数を使用して割当ておよび解放できます。ユーザーは、OCIArrayDescriptorAlloc()関数およびOCIArrayDescriptorFree()関数をそれぞれ使用して、記述子の配列の割当ておよび解放を行うことができます。

JSONドキュメント構造の例を次の図に示します。

図23-1 JSONドキュメントの例

図23-1の説明が続きます
「図23-1 JSONドキュメントの例」の説明

OCIJsonDomDocGet()関数を使用すると、JsonDomDoc *で表される基礎となるJSON DOM (Document Object Model)コンテナへの参照を取得できます。JSON DOMドキュメントには、オブジェクト型、配列型またはスカラー型のいずれかのノードが含まれています。

表23-1 型の作成および定数

プログラム変数 型定数
JsonDomScalar JZNDOM_SCALAR
JsonDomArray JZNDOM_ARRAY
JsonDomObject JZNDOM_OBJECT

ノート:

JsonDomNodeは不完全な型です。前述の表に示されている型の値は、(JsonDomNode *)型に設定できます。

23.2 リリース21cより前のクライアント・ライブラリと互換性

この項では、Oracle Databaseリリース21cより前のクライアント・バージョンをJSONデータ型の問合せに互換性を持たせる方法について説明します。

Oracle Databaseリリース21c以降、JSONデータ型はRDBMSサーバーの21cバージョンとクライアント・ライブラリの21cバージョンの両方でサポートされます。このサポートにより、クライアント・プログラムはJSONデータを問い合せ、ネイティブにデコードできるOSONバイトを受信できます。パフォーマンス向上のためにこの方法をお薦めします。

インスタント・クライアント・バージョンを21cに更新しない場合でも、アプリケーションはJSON型の列のデータを文字列として引き続き読み書きできます。したがって、C OCIプログラムでデータを問い合せるには、SQLT_CHRSQLT_BLOBまたは SQLT_CLOBデータ型を使用して定義できます。JSONデータがBLOBデータとして抽出される場合、古いクライアントと新しいクライアントの両方について、JSONテキストはUTF-8エンコードされます。結果はJSONテキスト形式です。定義タイプとしてSQLT_CHRを使用する場合、JSONテキスト・サイズは32 Kのみに制限されます。SQLT_CHRからサイズ制限を回避するには、定義変数の型としてSQLT_CLOBまたはSQLT_BLOBを使用する必要があります。

JSON型の列の問合せ方法を次のコード・スニペットに示します。

void testDescribe()
{
  oratext     stmt[400] = {0};
  ub4         stmtlen;
  ub4         numcols;
  ub4         i;
  OCIStmt    *stmthp;
  OCIParam *colhd = (OCIParam *) 0;
  OCIAuthInfo *authhp = (OCIAuthInfo *)0;
  sword status;

  getSession(&authhp);


  strcpy(stmt, "SELECT jcol FROM jtab where rownum < 2");
  stmtlen = strlen(stmt);

  Checkerr(errhp,
               OCIStmtPrepare2(svchp, &stmthp, errhp, stmt, stmtlen,
                               (oratext *)0, (ub4)0, (ub4) OCI_NTV_SYNTAX,
                               (ub4) OCI_DEFAULT), "OCIStmtPrepare2");

  printf("\n########### Describe-only test  #############\n");

  Checkerr(errhp,
               OCIStmtExecute(svchp, stmthp, errhp, 0, 0,
                              (OCISnapshot *)0, (OCISnapshot *)0,
                              OCI_DESCRIBE_ONLY), "OCIStmtExecute");

  /* Get the number of columns in the query */
  Checkerr(errhp,
               OCIAttrGet((void *)stmthp, OCI_HTYPE_STMT, (void *)&numcols,
                           (ub4 *)0, OCI_ATTR_PARAM_COUNT, errhp), "OCIAttrGet");

  for (i = 1; i <= numcols; i++)
  {
    ub4 type = 0;

    Checkerr(errhp,
                 OCIParamGet((void *)stmthp, OCI_HTYPE_STMT, errhp,
                 (void **)&colhd, i), "OCIStmtParamGet");

    Checkerr(errhp,
                 OCIAttrGet((void*)colhd, OCI_DTYPE_PARAM, (void*)&type,
                            (ub4 *)0, OCI_ATTR_DATA_TYPE, errhp), "OCIAttrGet");

    printf("Col %d type %d\n", i, type);
  }

  releaseSession(authhp);
}

次に、実行を記述する前述のコードの出力で、JSON型の列の型としてBLOBが返されることを示します。

########### Describe-only test  #############
Col 1 type 113

23.3 可変DOMと不変DOM

この項では、JSON DOMの可変形式および不変形式について説明します。

OCI記述子を使用すると、可変DOMまたは不変DOMの2つの形式のJSON DOMのいずれかを取得できます。可変DOM内のDOMノードは変更できます。それに対して、不変DOMは読取り専用であり、DOMに対して書込み操作を行うとエラーが発生します。記述子によって保持されるデフォルトのDOMは、OCIAttrSet()関数を使用してブール属性型に変更されないかぎり、不変です。

ノート:

OCIJsonDomDocSet()関数を使用して、記述子にJSON DOMコンテナを設定できます。ソースDOMは、記述子の形式と異なる形式にすることができます。つまり、ソースを可変DOMにして、ターゲット記述子に不変DOMを設定できます。

23.3.1 可変DOMとしてのJSONのマニフェスト

OCIクライアント・アプリケーションでは、JSONのコンテンツを可変DOMとしてマニフェストできます。XDKのC DOM関数を使用すると、JSONドキュメントとの間でJSON要素(オブジェクト、配列、スカラーなど)の読取りおよび書込みを行うことができます。

次のコード・スニペットの例は、OCIJson*記述子との間で可変モードでDOMドキュメントの参照を設定する方法を示しています。

/* Set the JSON DOM MUTABLE Attribute to TRUE */
boolean attr = TRUE;
rc = OCIAttrSet(jsond,                  /* OCIJson descriptor */  
         OCI_DTYPE_JSON,                /* Descriptor type */ 
         &attr,                 
         OCI_ATTR_JSON_DOM_MUTABLE,     /* Attribute type */
         errhp);
if (rc != OCI_SUCCESS)  goto err_hndlr;  

OCI_ATTR_JSON_DOM_MUTABLE記述子属性にTRUEを設定するには、OCIAttrSet()を使用します。

OCIアプリケーションでは、次のタイプのJSON入力を記述子に設定することもできます。
  • バッファ入力 – oratext*
  • ストリーミング入力 – orastream *

23.3.2 不変DOMとしてのJSONのマニフェスト

OCIクライアント・アプリケーションは、バイナリJSONに基づく不変の線形バイナリ・バッファとしてJSONコンテンツをマニフェストできます。

次のコード・スニペットの例は、OCIJson*記述子との間で不変モードでDOMドキュメントの参照を設定する方法を示しています。この設定を記述子に対して行わない場合は、値FALSEにデフォルト設定されます。

/* Set the JSON DOM IMMUTABLE Attribute to FALSE */ 
boolean attr = FALSE; 
rc = OCIAttrSet(jsond,                        /* OCIJson descriptor */
                OCI_DTYPE_JSON,               /* Descriptor Type */                 
                &attr,          
                OCI_ATTR_JSON_DOM_MUTABLE,    /* Attribute type */                 
                errhp); 
if (rc != OCI_SUCCESS)  goto err_hndlr;
  
JSON記述子のOCI_ATTR_JSON_DOM_MUTABLEFALSEを設定するには、OCIAttrSet()を使用します。
OCIアプリケーションでは、次のタイプのJSON入力を記述子に設定することもできます。
  • バッファ入力 – oratext*
  • ストリーミング入力 – orastream *

23.4 JSONデータの書込みおよび読取りのコール順序

この項では、データベースへのJSONデータの書込みおよび読取りのコール順序について説明します。

データベースにJSONデータを書き込むためのコール順序を次の図に示します。

図23-2 JSONデータを書き込むためのコール順序

図23-2の説明が続きます
「図23-2 JSONデータを書き込むためのコール順序」の説明
データベースのJSONデータを読み取るためのコール順序を次の図に示します。

図23-3 JSONデータを読み取るためのコール順序

図23-3の説明が続きます
「図23-3 JSONデータを読み取るためのコール順序」の説明

23.5 JSON DOMの操作

この項では、様々なJSON DOMの操作について説明します。

23.5.1 スカラー型のマッピング

この項では、サポートされるスカラー型のマッピングをリストして説明します。

テキストJSONでは、標準JSON言語のスカラー型のみがサポートされます。ただし、JSONデータのSQL型がJSONの場合、Oracle Databaseでは標準のJSON言語型のセットが拡張されており、SQLスカラー・データ型(binary、date、timestamp、double、float、year-month interval、day-second intervalなど)に直接対応する複数のスカラー型が含まれています。

これと同様に、プログラム変数は拡張スカラー型に直接マッピングされるため、OCIJsonを使用してデータベースからJSON値がフェッチされます。これらのプリミティブ型のマッピングのサマリーを次の表に示します。

表23-2 スカラー型のマッピング

JSONスカラー型 データベースのSQL型 OCI SQL型定数 OCIプログラム変数 JSONスカラー型定数

String

VARCHAR2

SQLT_CHR

oratext[n] JZNVAL_STRING

Number

NUMBER

SQLT_VNU

OCINumber* JZNVAL_ORA_NUMBER

True (Boolean)

該当なし

該当なし 該当なし JZNVAL_TRUE

False (Boolean)

該当なし 該当なし 該当なし JZNVAL_FALSE

Binary

RAW

SQLT_BIN

ub1[n] JZNVAL_BINARY

Double

BINARY_DOUBLE

SQLT_BDOUBLE

double JZNVAL_DOUBLE

Float

BINARY_FLOAT SQLT_BFLOAT float JZNVAL_FLOAT

Date

DATE

SQLT_ODT

JsonDateTime* JZNVAL_ORA_DATE

Timestamp

TIMESTAMP

SQLT_TIMESTAMP

JsonDateTime* JZNVAL_ORA_TIMESTAMP
タイムゾーン付きタイムスタンプ TIMESTAMP WITH TIMEZONE SQLT_TIMESTAMP_TZ JsonDateTime* JZNVAL_ORA_TIMESTAMPTZ

Day-Second Interval

INTERVALDAYTOSECOND

SQLT_INTERVAL_DS

JsonDayInterval* JZNVAL_ORA_DAYSECOND_DUR

Year-Month Interval

INTERVALYEARTOMONTH

SQLT_INTERVAL_YM

JsonYearInterval* JZNVAL_ORA_YEARMONTH_DUR

Null

該当なし 該当なし 該当なし JZNVAL_NULL

23.5.2 JSON DOMスカラー・ノードの読取り

この項では、JSON DOMスカラー・ノードを読み取る方法について説明します。

OCIは、バイナリの単精度浮動小数点と倍精度浮動小数点をIEEEの単精度浮動小数点形式および倍精度浮動小数点形式に暗黙的に変換します。number、timestamp、day-second intervalおよびyear-month interval型の場合は、JsonOCIVal *型を使用し、JsonDomGetScalarInfoOci()関数を使用して構造化された形式でデータを読み取ることができます。JsonOCIVal *は、次のコード・スニペットに示されているように定義されたCの共用体です。

/* Auxiliary Union of helper structures */
typedef union JsonOCIVal
{
  JsonDateTime      dt_JsonOCIVal;
  JsonDayInterval   dayInv_JsonOCIVal;
  JsonYearInterval  yrInv_JsonOCIVal;
  ub1               num_JsonOCIVal[JZN_ORA_NUM_MAX_LEN];
} JsonOCIVal;
次のコード・スニペットは、JSON DOMからスカラー・ノードの値をフェッチする方法を示しています。

#include <ocijson.h>
void introspectDomNode(appctx         *c,
                       JsonDomDoc     *doc,
                       JsonDomNode    *node)
{
  JsonOCIVal     av;
  jznScalarVal   sval;
  jznnodetype    ntype;
  /* Check the JSON node type */
  ntype =  JsonDomGetNodeType(doc, node);
  if (ntype == JZNDOM_SCALAR)
  {
    /* Get information for this JSON scalar node */
    JsonDomGetScalarInfoOci(doc, (JsonDomScalar *)node, &sval, &av);
    printScalarInfo(c, &sval, &av);
  }
  else if (ntype == JZNDOM_ARRAY) {...}
  else if (ntype == JZNDOM_OBJECT) {...}
  ...
}
void printScalarInfo(appctx          *c, 
                     jznScalarVal    *sval,
                     JsonOCIVal      *av)
{
  jznvaltype       vtype = sval->type_jznScalarVal;
  ub4              i;
  switch (vtype)
  {
    case JZNVAL_STRING:
      printf("Type: JZNVAL_STRING\n");
      printf("Value: %.*s\n", sval->len_jznScalarVal, sval->val_jznScalarVal);
    break;
    case JZNVAL_BINARY:
      printf("Type: JZNVAL_BINARY\n");
      printf("Value: ");
      for (i = 0 ; i < sval->binlen_jznScalarVal; i++)
        printf("%X", (sval->binval_jznScalarVal)[i]);
      printf("\n");
    break;
    case JZNVAL_FLOAT:
      printf("Type: JZNVAL_FLOAT\n");
      printf("Value: %f\n", sval->flt_jznScalarVal);
    break;
    case JZNVAL_DOUBLE:
      printf("Type: JZNVAL_DOUBLE\n");
      printf("Value: %lf\n", sval->db_jznScalarVal);
    break;
    case JZNVAL_TRUE:
      printf("Type: JZNVAL_TRUE\n");
    break;
    case JZNVAL_FALSE:
      printf("Type: JZNVAL_FALSE\n");
    break;
    case JZNVAL_NULL:
      printf("Type: JZNVAL_NULL\n");
    break;
    case JZNVAL_ORA_NUMBER:
    {
      double  nval;
      printf("Type: JZNVAL_ORA_NUMBER\n");
      OCINumberToReal(c->errhp, (const OCINumber *) av, (uword) sizeof(nval), &nval);          
      printf("Value: %d\n", nval);
      break;
    }
    case JZNVAL_ORA_DATE:
    {
      JsonDateTime  *ts;
      printf("Type: JZNVAL_ORA_DATE\n");
      ts = &(av->dt_JsonOCIVal);
      printf("Value: %d-%d-%d\n", ts->year_JsonDateTime, ts->month_JsonDateTime,
             ts->day_JsonDateTime);
      break;
    }
    case JZNVAL_ORA_TIMESTAMP:
    {
      JsonDateTime  *ts;
      printf("Type: JZNVAL_ORA_TIMESTAMP\n");
      ts = &(av->dt_JsonOCIVal);
      printf("Value: %d-%d-%d %d:%d:%d:%d\n", ts->year_JsonDateTime,
             ts->month_JsonDateTime, ts->day_JsonDateTime, ts->hour_JsonDateTime,
             ts->minute_JsonDateTime, ts->second_JsonDateTime,
             ts->fsecond_JsonDateTime);
      break;
    }
    case JZNVAL_ORA_TIMESTAMPTZ:
    {
      JsonDateTime  *ts;
      printf("Type: JZNVAL_ORA_TIMESTAMPTZ\n");
      ts = &(av->dt_JsonOCIVal);
      printf("Value: %d-%d-%d %d:%d:%d:%d %03d:%02d\n", ts->year_JsonDateTime,
             ts->month_JsonDateTime, ts->day_JsonDateTime, ts->hour_JsonDateTime,
             ts->minute_JsonDateTime, ts->second_JsonDateTime,
             ts->fsecond_JsonDateTime, ts->tzHourOffset_JsonDateTime,
             ts->tzMinuteOffset_JsonDateTime);
      break;
    }

    case JZNVAL_ORA_YEARMONTH_DUR:
    {
      JsonYearInterval  *yint;
      printf("Type: JZNVAL_ORA_YEARMONTH_DUR\n");
      yint = &(av->yrInv_JsonOCIVal);
      printf("Value: %dY-%dM\n",
             yint->years_JsonYearInterval, yint->months_JsonYearInterval);
      break;
    }
    case JZNVAL_ORA_DAYSECOND_DUR:
    {
      JsonDayInterval *dint;
      printf("Type: JZNVAL_ORA_DAYSECOND_DUR\n");
      dint = &(av->dayInv_JsonOCIVal);
      printf("Value: %dD-%dH-%dM-%dS-%dSS\n",
             dint->days_JsonDayInterval, dint->hours_JsonDayInterval,
             dint->minutes_JsonDayInterval, dint->seconds_JsonDayInterval,
             dint->fseconds_JsonDayInterval);
      break;
    }
    default:
      printf("ERROR: Unsupported value type encountered [%d]\n", vtype);
    break;
  }
}

23.5.3 JSON DOMの作成

この項では、JSON DOMの作成方法について説明します。

23.5.3.1 JSONスカラー型とスカラー・コンストラクタ

この項では、JSONスカラー型および対応するスカラー・コンストラクタを示します。

可変DOMでは、新しいノードを追加したり、既存のノードを変更したりできます。次の表に、スカラー型およびその対応するコンストラクタ関数を示します。

表23-3 スカラー型とコンストラクタ

JSONスカラー型 スカラー・コンストラクタ

JZNVAL_STRING

JsonDomCreateString

JZNVAL_ORA_NUMBER

JsonDomCreateOCINumber

JZNVAL_TRUE

JsonDomCreateBoolean

JZNVAL_FALSE

JsonDomCreateBoolean

JZNVAL_BINARY

JsonDomCreateBinary

JZNVAL_DOUBLE

JsonDomCreateDouble

JZNVAL_FLOAT

JsonDomCreateFloat

JZNVAL_ORA_DATE

JsonDomCreateOCIDate

JZNVAL_ORA_TIMESTAMP

JsonDomCreateOCIDateTime

JZNVAL_ORA_TIMESTAMPTZ JsonDomCreateOCIDateTime

JZNVAL_NULL

JsonDomCreateNull

JZNVAL_ORA_YEARMONTH_DUR JsonDomCreateOCIInteval
JZNVAL_ORA_DAYSECOND_DUR JsonDomCreateOCIInteval

非スカラー型のコンストラクタ関数

次の表に、非スカラー型(配列およびオブジェクト)のコンストラクタ関数を示します。
JSONノード・タイプ スカラー・コンストラクタ
JZNDOM_ARRAY JsonDomCreateArray
JZNDOM_OBJECT JsonDomCreateObject

ノート:

JsonDomSetField()関数を使用すると、指定したフィールドの値をDOM内の指定したオブジェクトに設定できます。

関連項目:

JSON DOM関数
23.5.3.2 スカラー・ノードを使用したDOMの作成

この項では、様々な型のスカラー・ノードを使用してDOMを作成する方法について説明します。

次のコードは様々な型のスカラー・ノードを使用してDOMを作成する方法を示しており、このコードは次の操作を実行します。
  1. JSON記述子を割り当て、可変プロパティを設定します
  2. 様々な型(string、number、boolean、binary、double、float、date、timestamp、null)のスカラー・ノードを作成し、これらのノードをDOMに追加します
  3. 記述子にJSON DOMコンテナを設定します
  4. JSON記述子をテキストにシリアライズします
  5. 記述子を解放します

#include <ocijson.h>
 
sword buildDom(appctx          *c,
               JsonDomDoc      *jdoc,
               JsonDomObject   *root,
               boolean          ismut)
{
 
  OCIJson        *jsond;
  oratext         outbuf[1024] = {0};
  oraub8          outlen       = 1024;
  JsonDomScalar  *node;
 
  /* Field names */
  oratext        *s_name     = (oratext *) "string_val";
  oratext        *n_name     = (oratext *) "number_val";
  oratext        *bt_name    = (oratext *) "true_val";
  oratext        *bf_name    = (oratext *) "false_val";
  oratext        *b_name     = (oratext *) "binary_val";
  oratext        *d_name     = (oratext *) "double_val";
  oratext        *f_name     = (oratext *) "float_val";
  oratext        *dt_name    = (oratext *) "date_val";
  oratext        *dtt_name   = (oratext *) "datetime_val";
  oratext        *dttz_name  = (oratext *) "datetimetz_val";
  oratext        *yminv_name = (oratext *) "yminterval_val";
  oratext        *dsinv_name = (oratext *) "dsinterval_val";
  oratext        *nl_name    = (oratext *) "null_val";
 
  /* Values */
  oratext        *sval    = (oratext *) "Strings are sequence of characters";
  ub4             slen    = (ub4) strlen(sval);
  int             inval   = -29873546;
  OCINumber       nval;
  boolean         btval   = TRUE;
  boolean         bfval   = FALSE;
  ub1             bval[8] = {0x000D, 0x000E, 0x000A, 0x000D,
                             0x000B, 0x000E, 0x000E, 0x000F};
  ub4             blen    = (ub4) 8;
  double          dval    = 34837749.5699837;
  float           fval    = -133424.75;
  OCIDate        *odval   = NULL;
  sb2             yrval   = 2020;
  ub1             mnval   = 10;
  ub1             dyval   = 25;
  OCIDateTime    *odtval  = NULL;
  ub1             hrval   = 8;
  ub1             minval  = 32;
  ub1             secval  = 56;
  ub4             fsecval = 123456789;
  OCIDateTime    *odtzval = NULL;
  oratext        *tzone   = (oratext *)"-05:30";
  ub4             tzlen   = (ub4) strlen(tzone);
  OCIInterval    *yminval = NULL;
  oratext        *yminvt  = (oratext *)"04-11";
  OCIInterval    *dsinval = NULL;
  oratext        *dsinvt  = (oratext *)"11 10:36:19.000005";
 
 
  /* (1) Allocate JSON descriptor and set mutable property */
  checkerr("Allocate JSON descriptor", c,
            OCIDescriptorAlloc(c->envhp, (void **) &jsond,
                                OCI_DTYPE_JSON, 0, 0));
  checkerr("Attr set mutable", c,
            OCIAttrSet((void *) jsond, OCI_DTYPE_JSON, &ismut, 0,
                        OCI_ATTR_JSON_DOM_MUTABLE, c->errhp));
 
  /* (2) Create scalar fields and add to DOM */
  /* (a) Add string field */
  node = JsonDomCreateString(jdoc, sval, slen);
  JsonDomSetField(jdoc, root, s_name, (ub2) strlen(s_name),
                  (JsonDomNode *) node);
 
  /* (b) Add number field */
  checkerr("Create OCINumber", c,
           OCINumberFromInt(c->errhp, &inval, sizeof(int), OCI_NUMBER_SIGNED,
                            &nval));
  node = JsonDomCreateOCINumber(jdoc, &nval);
  JsonDomSetField(jdoc, root, n_name, (ub2) strlen(n_name),
                  (JsonDomNode *) node);
 
  /* (c) Add boolean TRUE field */
  node = JsonDomCreateBoolean(jdoc, btval);
  JsonDomSetField(jdoc, root, bt_name, (ub2) strlen(bt_name),
                  (JsonDomNode *) node);
 
  /* (d) Add boolean FALSE field */
  node = JsonDomCreateBoolean(jdoc, bfval);
  JsonDomSetField(jdoc, root, bf_name, (ub2) strlen(bf_name),
                  (JsonDomNode *) node);
 
  /* (e) Add binary field */
  node = JsonDomCreateBinary(jdoc, bval, blen);
  JsonDomSetField(jdoc, root, b_name, (ub2) strlen(b_name),
                  (JsonDomNode *) node);
 
  /* (f) Add double field */
  node = JsonDomCreateDouble(jdoc, dval);
  JsonDomSetField(jdoc, root, d_name, (ub2) strlen(d_name),
                  (JsonDomNode *) node);
 
  /* (g) Add float field */
  node = JsonDomCreateFloat(jdoc, fval);
  JsonDomSetField(jdoc, root, f_name, (ub2) strlen(f_name),
                  (JsonDomNode *) node);
 
  /* (h) Add date field */
  checkerr("Create OCIDate", c,
           OCIDescriptorAlloc(c->envhp, (void **) &odval, OCI_DTYPE_DATE,
                              0, NULL));
  OCIDateSetDate(odval, yrval, mnval, dyval);
  node = JsonDomCreateOCIDate(jdoc, odval);
  JsonDomSetField(jdoc, root, dt_name, (ub2) strlen(dt_name),
                  (JsonDomNode *) node);
 
  /* (i) Add datetime field */
  checkerr("Create OCIDateTime", c,
           OCIDescriptorAlloc(c->envhp, (void **) &odtval, OCI_DTYPE_TIMESTAMP,
                              0, NULL));
  checkerr("Construct OCIDateTime timezone", c,
           OCIDateTimeConstruct (c->envhp, c->errhp, odtval,
                                 yrval-10, mnval-5, dyval-10,
                                 hrval, minval, secval, fsecval, NULL, 0));
  node = JsonDomCreateOCIDateTime(jdoc, odtval);
  JsonDomSetField(jdoc, root, dtt_name, (ub2) strlen(dtt_name),
                  (JsonDomNode *) node);
 
  /* (j) Add datetime timezone field */
  checkerr("Create OCIDateTime timezone", c,
           OCIDescriptorAlloc(c->envhp, (void **) &odtzval, OCI_DTYPE_TIMESTAMP_TZ,
                              0, NULL));
  checkerr("Construct OCIDateTime timezone", c,
           OCIDateTimeConstruct (c->envhp, c->errhp, odtzval,
                        yrval-7, mnval-3, dyval-2,
                        hrval-1, minval-10, secval-25, fsecval-98765432,
                        tzone, tzlen));
  node = JsonDomCreateOCIDateTime(jdoc, odtzval);
  JsonDomSetField(jdoc, root, dttz_name, (ub2) strlen(dttz_name),
                  (JsonDomNode *) node);
 
  /* (k) Add year-month interval field */
  checkerr("Create OCIInterval year-month", c,
           OCIDescriptorAlloc(c->envhp, (void **) &yminval, OCI_DTYPE_INTERVAL_YM,
                              0, NULL));
  checkerr("Construct OCIInterval year-month", c,
           OCIIntervalFromText(c->envhp, c->errhp, yminvt, strlen(yminvt), yminval));
  node = JsonDomCreateOCIInterval(jdoc, yminval);
  JsonDomSetField(jdoc, root, yminv_name, (ub2) strlen(yminv_name),
                  (JsonDomNode *) node);
 
  /* (l) Add day-second interval field */
  checkerr("Create OCIInterval day-second", c,
           OCIDescriptorAlloc(c->envhp, (void **) &dsinval, OCI_DTYPE_INTERVAL_DS,
                              0, NULL));
  checkerr("Construct OCIInterval day-second", c,
           OCIIntervalFromText(c->envhp, c->errhp, dsinvt, strlen(dsinvt), dsinval));
  node = JsonDomCreateOCIInterval(jdoc, dsinval);
  JsonDomSetField(jdoc, root, dsinv_name, (ub2) strlen(dsinv_name),
                  (JsonDomNode *) node);
 
  /* (m) Add NULL field */
  node = JsonDomCreateNull(jdoc);
  JsonDomSetField(jdoc, root, nl_name, (ub2) strlen(nl_name),
                  (JsonDomNode *) node);
 
  /* (3) Set the JSON DOM container in the descriptor */
  checkerr("Set JSON DOM container", c,
            OCIJsonDomDocSet(c->svchp, jsond, jdoc, c->errhp, 0));
 
  /* (4) Serialize JSON descriptor to text */
  checkerr("To Text Buffer", c,
            OCIJsonToTextBuffer(c->svchp, jsond, outbuf, &outlen,
                                JZNU_PRINT_PRETTY, c->errhp,
                                OCI_JSON_TEXT_ENV_NLS));
  printf("Descriptor content:\n");
  printf("%.*s \n", outlen, outbuf);
 
finally:
 
  /* (5) Free the descriptors */
  if (odval)
    checkerr("Free Date descriptor", c,
              OCIDescriptorFree(odval, OCI_DTYPE_DATE));
  if (odtval)
    checkerr("Free DateTime descriptor", c,
              OCIDescriptorFree(odtval, OCI_DTYPE_TIMESTAMP));
  if (odtzval)
    checkerr("Free DateTime timezone descriptor", c,
              OCIDescriptorFree(odtzval, OCI_DTYPE_TIMESTAMP_TZ));
  if (yminval)
    checkerr("Free Interval year-month descriptor", c,
              OCIDescriptorFree(yminval, OCI_DTYPE_INTERVAL_YM));
  if (dsinval)
    checkerr("Free Interval day-second descriptor", c,
              OCIDescriptorFree(dsinval, OCI_DTYPE_INTERVAL_DS));
  if (jsond)
    checkerr("Free JSON descriptor", c,
              OCIDescriptorFree(jsond, OCI_DTYPE_JSON));
 
  return c->status;
}

関数printScalarInfo()の出力は次のとおりです。

ノート:

すべてのタイプ情報が保持されます
Key: "string_val"
Type: JZNVAL_STRING
Value: Strings are sequence of characters

Key: "number_val"
Type: JZNVAL_ORA_NUMBER
Value: -29873546.000000

Key: "true_val"
Type: JZNVAL_TRUE

Key: "false_val"
Type: JZNVAL_FALSE

Key: "binary_val"
Type: JZNVAL_BINARY
Value: DEADBEEF

Key: "double_val"
Type: JZNVAL_DOUBLE
Value: 34837749.569984

Key: "float_val"
Type: JZNVAL_FLOAT
Value: -133424.750000

Key: "date_val"
Type: JZNVAL_ORA_DATE
Value: 2020-10-25

Key: "datetime_val"
Type: JZNVAL_ORA_TIMESTAMP
Value: 2010-5-15 8:32:56:123456789

Key: "datetimetz_val"
Type: JZNVAL_ORA_TIMESTAMPTZ
Value: 2013-7-23 7:22:31:24691357 -05:-30

Key: "yminterval_val"
Type: JZNVAL_ORA_YEARMONTH_DUR
Value: 4Y-11M

Key: "dsinterval_val"
Type: JZNVAL_ORA_DAYSECOND_DUR
Value: 11D-10H-36M-19S-5000SS

Key: "null_val"
Type: JZNVAL_NULL
OCIJsonToTextBuffer()関数は、次のテキストJSONの出力を戻します。

ノート:

拡張型は失われ、文字列に変換されます。
{
  "true_val" : true,
  "number_val" : -29873546,
  "string_val" : "Strings are sequence of characters",
  "date_val" : "2020-10-25T00:00:00",
  "dsinterval_val" : "P11DT10H36M19.000005S",
  "yminterval_val" : "P4Y11M",
  "datetime_val" : "2010-05-15T08:32:56.123456789",
  "binary_val" : "0D0E0A0D0B0E0E0F",
  "null_val" : null,
  "false_val" : false,
  "datetimetz_val" : "2013-07-23T07:22:31.024691357-05:30",
  "float_val" : -133424.75,
  "double_val" : 34837749.5699837
}

関連項目:

JSON DOM関数

23.6 JSON記述子を使用したマルチスレッド

OCIJson*記述子はスレッド・セーフではありません。記述子とその子孫のDOMノードが一度に1つのスレッドのみで操作されるようにすることは、ユーザーの責任です。

23.7 文字セットの処理

OCIでは、テキスト入力の文字セットは、OCI環境ハンドルの設定によって異なります。

OCIEnv*の作成時にユーザーがcsidパラメータを指定しない場合、NLS_LANG設定がハンドルのデフォルト設定として使用されます。テキストJSONが入力であるOCIJsonTextBufferParse()OCIJsonTextStreamParse()などのAPIの場合、入力は、Oracleで認識される任意の文字セットにすることができ(JSON構文に準拠している場合)、環境ハンドルまたはNLS_LANGパラメータに設定されている文字セットである必要はありません。

ノート:

Unicodeでエンコードされた入力にJZN_INPUT_DETECTを使用する場合、入力のエンコーディングはUTF-8、UTF-16 (LEまたはBE)のいずれかとして検出され、それに応じて処理されます。テキストJSONの入力がこのモードのUnicodeのエンコーディングのいずれかではない場合は、ユーザー・エラーであり、動作は保証されません。

OCI_JSON_TEXT_ENV_NLSモードが設定されている場合を除き、OCIJson API (OCIJsonToTextBuffer ()OCIJsonToTextStream ()など)は、テキストJSONをAL32UTF8文字セットで戻します。

23.8 スキーマ検証のOCIインタフェース

OCIアプリケーションでJSONスキーマ検証を実行するためのOCIインタフェース。

用途

JSONスキーマに対してJSONドキュメント・インスタンスを検証します。詳細なエラー・メッセージは、エラーJSON記述子のJSONインスタンスとして報告されます。

構文

sword OCIJsonSchemaValidate (
    OCISvcCtx    *svchp,
    OCIJson      *jsond,
    OCIJson      *schemad,
    ub4           sflags,
    OCIJson      *errors,
    ub1           errmode,
    OCIError     *errhp,
    ub4           mode
);

パラメータ

svchp IN

割り当てられているOCIサービス・コンテキスト・ハンドル。

jsond IN

JSON記述子としてのドキュメント・インスタンス。

schemad IN

JSON記述子としてのスキーマ・インスタンス。

sflags IN

スキーマ・フラグ。

errors IN/OUT

JSON記述子として返されたエラー・メッセージ。

errmode IN
エラーのモード。次の値が有効です。
  • OCI_JSON_SCHEMA_ERROR_NONE: リクエストされたエラー・メッセージはありません。
  • OCI_JSON_SCHEMA_ERROR_SIMPLE: ブール・フィールドのみ。
  • OCI_JSON_SCHEMA_ERROR_BASIC: エラー出力ユニットのフラット・リスト。
errhp IN/OUT

割り当てられているOCIエラー・ハンドルです。

mode IN

実行のモードを指定します。

  • OCI_DEFAULT: デフォルト・モードです。この操作は、特別なモードなしでそのまま実行されます。
サーバー・ラウンドトリップ
0または1
戻り値
  • OCI_SUCCESS: スキーマ検証が成功した場合。
  • OCI_ERROR: OCIErrorパラメータに必要なエラー情報があります。リクエストされたエラー・モードに基づいて、エラーJSONディスクリプタで詳細を確認できます。

関連項目:

JSONスキーマ

23.9 列にJSONスキーマ制約があるかどうかを確認する属性

OCI属性OCI_ATTR_HAS_JSON_SCHEMAは、列にJSONスキーマ制約があるかどうかをチェックします。

例23-1 OCI_ATTR_HAS_JSON_SCHEMA属性の使用

SYNTAX
  ub1  has_schema;

tkpgjsCheck("Get ith column handle", c,
            OCIParamGet(collsthd, OCI_DTYPE_PARAM, c->errhp,
                        (void **) &colhd, i));

tkpgjsCheck("OCI_ATTR_HAS_JSON_SCHEMA", c,
            OCIAttrGet(colhd, OCI_DTYPE_PARAM, &has_schema, (ub4 *)0,
                       OCI_ATTR_HAS_JSON_SCHEMA, c->errhp));

printf("OCI_ATTR_HAS_JSON_SCHEMA: %d\n", has_schema);