Oracle Database 23c Free - Developer ReleaseでSQL*Loaderを使用したSODAコレクションへのデータロードを試してみた

# はじめに

Oracle Database 23cから、SQL*Loaderを使用して、スキーマレス・ドキュメント（JSONやXMLベースのアプリケーションデータなどの固定データ構造を持たないドキュメント）をSODA（Simple Oracle Document Access）コレクションとしてOracle Databaseにロードできるようになりました。

SODA（Simple Oracle Document Access）の詳細は、こちらのマニュアルを参照してください。

https://docs.oracle.com/cd/F58798_01/index.html

ということで、早速試してみました。
# 1. DBユーザの作成
SQL*Plusから管理者ユーザとしてOracle Database 23c Free - Developer Releaseのデータベース（コンテナ・データベース）に接続します。
```
[oracle@oracle23c ~]$ sqlplus / as sysdba

SQL*Plus: Release 23.0.0.0.0 - Developer-Release on Wed Jun 14 02:41:32 2023
Version 23.2.0.0.0

Copyright (c) 1982, 2023, Oracle.  All rights reserved.


Connected to:
Oracle Database 23c Free, Release 23.0.0.0.0 - Developer-Release
Version 23.2.0.0.0

SQL>
```
プラガブル・データベースfreepdb1に接続します。
```
SQL> ALTER SESSION SET CONTAINER = freepdb1;

Session altered.

SQL>
```
ユーザtestuserを作成し、必要な権限（ロール）を付与します。

**SODA_APP**ロール：SODA APIを使用して、特にドキュメント・コレクションを作成、削除およびリストする権限を提供するロール
**DB_DEVELOPER_ROLE**ロール：Oracle Database 23cで新しく登場した、アプリケーションを設計、構築およびデプロイするために必要なすべての権限をすばやく割り当てるためのロール
```
SQL> GRANT DB_DEVELOPER_ROLE, SODA_APP, UNLIMITED TABLESPACE TO testuser IDENTIFIED BY Test#1Test#1;

Grant succeeded.

SQL> 
```
ユーザtestuserが作成されました。

# 2.ロードするJSONデータの作成

SQL*Loaderを使用してSODAにロードするJSONデータを作成します。
今回はJSON_OBJECTファンクションを使用して、v$parameterビューからJSONデータを作成しました。
```
SQL> set linesize 300
SQL> set pagesize 1000
SQL> set head off
SQL> set feed off
SQL> spo json_data_base.txt
SQL> SELECT JSON_OBJECT('name' : name,
  2                     'type' : type,
  3                     'value' : value,
  4                     'isDefault' : isdefault,
  5                     'description' : description) output
  6  FROM v$parameter
  7  ORDER BY name;

{"name":"DBFIPS_140","type":1,"value":"FALSE","isDefault":"TRUE","description":"Enable use of crypographic libraries in FIPS mode, public"}
{"name":"_datafile_write_errors_crash_instance","type":1,"value":"FALSE","isDefault":"FALSE","description":"datafile write errors crash instance"}
{"name":"_db_writer_coalesce_area_size","type":6,"value":"16777216","isDefault":"FALSE","description":"Size of memory allocated to dbwriter for coalescing writes"}

＜中略＞

{"name":"xml_client_side_decoding","type":2,"value":"true","isDefault":"TRUE","description":"enable/disable xml client-side decoding"}
{"name":"xml_db_events","type":2,"value":"enable","isDefault":"TRUE","description":"are XML DB events enabled"}
{"name":"xml_handling_of_invalid_chars","type":2,"value":"raise_error","isDefault":"TRUE","description":"Handle invalid chars during xmlelement"}
SQL> 
```
SQL*Plusを終了します。
```
SQL> exit
Disconnected from Oracle Database 23c Free, Release 23.0.0.0.0 - Developer-Release
Version 23.2.0.0.0
[oracle@oracle23c ~]$
```
出力されたjson_data_base.txtからファイルの先頭にあるSQLの部分の行とファイル末尾の行を削除し、各行の行末のスペースを削除してjson_data.txtとして保存します。
```
[oracle@oracle23c ~]$ cat json_data_base.txt | sed -e '1,8d' | sed -e '$d' | sed 's/\s*$//' > json_data.txt
[oracle@oracle23c ~]$
```

# 3. SODAコレクションの作成
ユーザtestuserとしてSQL*Plusからプラガブル・データベースfreepdb1に接続します。
```
[oracle@oracle23c ~]$ sqlplus testuser/Test#1Test#1@freepdb1

SQL*Plus: Release 23.0.0.0.0 - Developer-Release on Wed Jun 14 02:47:02 2023
Version 23.2.0.0.0

Copyright (c) 1982, 2023, Oracle.  All rights reserved.


Connected to:
Oracle Database 23c Free, Release 23.0.0.0.0 - Developer-Release
Version 23.2.0.0.0

SQL>
```
SODAコレクションTestCollection1を作成します。
```
SQL> set serveroutput on
SQL> DECLARE
  2    l_collection  SODA_COLLECTION_T;
  3  BEGIN
  4    l_collection := DBMS_SODA.CREATE_COLLECTION('TestCollection1');
  5  
  6    IF l_collection IS NOT NULL THEN
  7      DBMS_OUTPUT.PUT_LINE('Collection ID : ' || l_collection.get_name());
  8    ELSE
  9      DBMS_OUTPUT.PUT_LINE('Collection does not exist.');  
 10    END IF;
 11  END;
 12  /
Collection ID : TestCollection1

PL/SQL procedure successfully completed.

SQL>
```
SQL*Plusを終了します。
```
SQL> exit
Disconnected from Oracle Database 23c Free, Release 23.0.0.0.0 - Developer-Release
Version 23.2.0.0.0
[oracle@oracle23c ~]$
```

# 4. SQL*Loaderを使用したSODAコレクションへのデータロード

SQL*Loaderの制御ファイルload_soda.ctlを作成します。
INFILEにロードするファイルの名前（ここではjson_data.txt）、INTO COLLECTIONにロード先のSODAコレクション（ここではTestCollection1'）を指定します。
```
[oracle@oracle23c ~]$ vi load_soda.ctl
```

```text:load_soda.ctl
LOAD DATA
INFILE 'json_data.txt'
APPEND
INTO COLLECTION TestCollection1
FIELDS TERMINATED BY '0x02'
($CONTENT)
```
作成した制御ファイルload_soda.ctlを使用して、SQL*Loaderを実行します。
```
[oracle@oracle23c ~]$ sqlldr userid=testuser/Test#1Test#1@freepdb1 control=load_soda.ctl log=load_soda.log

SQL*Loader: Release 23.0.0.0.0 - Developer-Release on Wed Jun 14 02:49:10 2023
Version 23.2.0.0.0

Copyright (c) 1982, 2023, Oracle and/or its affiliates.  All rights reserved.

Path used:      SODA Collection
Commit point reached - logical record count 250
Commit point reached - logical record count 500
Commit point reached - logical record count 522

SODA Collection TestCollection1:
  522 Rows successfully loaded.

Check the log file:
  load_soda.log
for more information about the load.
[oracle@oracle23c ~]$
```
ファイルjson_data.txtの内容（JSONドキュメント）が、SODAコレクションTestCollection1にロードされました。
SQL*Loaderのログファイルload_soda.logを確認してみます。
```
[oracle@oracle23c ~]$ cat load_soda.log

SQL*Loader: Release 23.0.0.0.0 - Developer-Release on Wed Jun 14 02:49:10 2023
Version 23.2.0.0.0

Copyright (c) 1982, 2023, Oracle and/or its affiliates.  All rights reserved.

Control File:   load_soda.ctl
Data File:      json_data.txt
  Bad File:     json_data.bad
  Discard File:  none specified
 
 (Allow all discards)

Number to load: ALL
Number to skip: 0
Errors allowed: 50
Bind array:     250 rows, maximum of 1048576 bytes
Continuation:    none specified
Path used:      SODA Collection

SODA Collection TestCollection1, loaded from every logical record.
Insert option in effect for this SODA collection: APPEND

   Column Name                  Position   Len  Term Encl Datatype
------------------------------ ---------- ----- ---- ---- ---------------------
$CONTENT                            FIRST     *           CHARACTER            
    Terminator string : '0x02'


SODA Collection TestCollection1:
  522 Rows successfully loaded.
  0 Rows not loaded due to data errors.
  0 Rows not loaded because all WHEN clauses were failed.
  0 Rows not loaded because all fields were null.


Space allocated for bind array:                  64500 bytes(250 rows)
Read   buffer bytes: 1048576

Total logical records skipped:          0
Total logical records read:           522
Total logical records rejected:         0
Total logical records discarded:        0

Run began on Wed Jun 14 02:49:10 2023
Run ended on Wed Jun 14 02:49:10 2023

Elapsed time was:     00:00:00.11
CPU time was:         00:00:00.03
[oracle@oracle23c ~]$
```
SQL*Loaderの処理が問題なく完了したことが確認できました。

# 4. SODAコレクションにロードしたデータの確認
ユーザtestuserとしてSQL*Plusからプラガブル・データベースfreepdb1に接続します。
```
[oracle@oracle23c ~]$ sqlplus testuser/Test#1Test#1@freepdb1

SQL*Plus: Release 23.0.0.0.0 - Developer-Release on Wed Jun 14 02:57:17 2023
Version 23.2.0.0.0

Copyright (c) 1982, 2023, Oracle.  All rights reserved.

Last Successful login time: Wed Jun 14 2023 02:49:10 +00:00

Connected to:
Oracle Database 23c Free, Release 23.0.0.0.0 - Developer-Release
Version 23.2.0.0.0

SQL>
```
v$parameterビューのレコード数を確認します。
```
SQL> SELECT COUNT(*) FROM v$parameter;

  COUNT(*)
----------
       522

SQL>
```
TestCollection1のレコード数を確認します。
```
SQL> SELECT COUNT(*) FROM "TestCollection1";

  COUNT(*)
----------
       522

SQL>
```
レコード数が一致していることがわかりました。
TestCollection1の構造を確認します。
```
SQL> desc "TestCollection1"
 Name					                   Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID					                       NOT NULL VARCHAR2(255)
 CREATED_ON				                   NOT NULL TIMESTAMP(6)
 LAST_MODIFIED				               NOT NULL TIMESTAMP(6)
 VERSION	                               NOT NULL VARCHAR2(255)
 DATA						                        JSON

SQL>
```
ロードしたドキュメントはDATA列に格納されています。
DATA列の内容を確認します。
```
SQL> set long 300
SQL> set pagesize 3000
SQL> SELECT data FROM "TestCollection1";

DATA
--------------------------------------------------------------------------------
{"name":"db_16k_cache_size","type":6,"value":"0","isDefault":"TRUE","description
":"Size of cache for 16K buffers"}

{"name":"db_2k_cache_size","type":6,"value":"0","isDefault":"TRUE","description"
:"Size of cache for 2K buffers"}

{"name":"db_32k_cache_size","type":6,"value":"0","isDefault":"TRUE","description
":"Size of cache for 32K buffers"}

{"name":"db_4k_cache_size","type":6,"value":"0","isDefault":"TRUE","description"
:"Size of cache for 4K buffers"}

＜中略＞

{"name":"xml_client_side_decoding","type":2,"value":"true","isDefault":"TRUE","d
escription":"enable/disable xml client-side decoding"}

{"name":"xml_db_events","type":2,"value":"enable","isDefault":"TRUE","descriptio
n":"are XML DB events enabled"}

{"name":"xml_handling_of_invalid_chars","type":2,"value":"raise_error","isDefaul
t":"TRUE","description":"Handle invalid chars during xmlelement"}


522 rows selected.

SQL> 
```
SQL*Loaderを使用して、SODAコレクションにオブジェクトをロードできることが確認できました。

# 参考情報
・[Simple Oracle Document Access (SODA)の概要](https://docs.oracle.com/cd/F19136_01/adsdi/index.html)
・[Oracle Database 23c Utility：SODA Collections and SQL*Loader](https://docs.oracle.com/en/database/oracle/oracle-database/23/sutil/oracle-sql-loader-concepts.html#GUID-8E6F0279-0A34-4FA8-8EE2-5E118E450415)
・[Oracle Database 23c Utility：Examples of Loading SODA Collections ](https://docs.oracle.com/en/database/oracle/oracle-database/23/sutil/loading-objects-oracle-sql-loader.html#GUID-F32319D5-B625-4FEA-854A-47B634FEDB33)