Blockchain Tableを試す(1) (Oracle Database 19c)

Oracle Database 19cはRelease Update (RU)にバグ・フィックスだけでなく新機能を追加する場合があります。本記事で紹介するBlockchain Tableも RU 19.10 で追加された新機能です。

# Blockchain Tableとは
Blockchain Tableは格納されるレコードの更新や削除を制限し、ハッシュ値によるデータの改竄をチェックする機能を持ったテーブルです。Immutable Tableをベースにしています。Blockchain Tableは通常のテーブル定義に加えて以下の設定を追加することができます。

- テーブル削除を制限する期間（Immutable Tableと同じ）
- レコード削除を制限する期間（Immutable Tableと同じ）
- レコード削除期間を変更できるか（Immutable Tableと同じ）
- ハッシュ値を計算するアルゴリズムとバージョン（Blockchain Table独自）

# 準備
Release Update 19.10 以降をインストールし、データベースに適用します。下記の例ではV$VERSIONビューを確認してRU 19.11が適用されていることを確認しています。

```
SQL> SELECT BANNER_FULL FROM V$VERSION;

BANNER_FULL
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.11.0.0.0
```

次に初期化パラメーターcompatibleを19.10.0.0.0以上に変更する必要があります。以下の例では19.11.0.0.0に変更しています。

```
SQL> SHOW PARAMETER COMPATIBLE

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
compatible                           string      19.11.0.0.0
noncdb_compatible                    boolean     FALSE
```

# 作成
Blockchain Tableの作成にはCREATE BLOCKCHAIN TABLE文を実行します。何もオプションを指定しない場合はエラーORA-00905が発生します。

```
SQL> CREATE BLOCKCHAIN TABLE block1 (c1 NUMBER, c2 VARCHAR2(10));
CREATE BLOCKCHAIN TABLE block1 (c1 NUMBER, c2 VARCHAR2(10))
                                                              *
行1でエラーが発生しました。:
ORA-00905: キーワードがありません。
```

最低限、テーブルの削除制限（NO DROP句）と、レコードの削除制限（NO DELETE句）、ハッシュ値計算アルゴリズム（HASING句）を指定します。HASHING USING句は現状では固定のようです。作成後は通常のテーブルと同様にINSERT文を実行できます。

```
SQL> CREATE BLOCKCHAIN TABLE block1 (c1 NUMBER, c2 VARCHAR2(10))
  2    NO DROP UNTIL 1 DAYS IDLE
  3    NO DELETE UNTIL 16 DAYS AFTER INSERT
  4    HASHING USING sha2_512 VERSION v1
  5    TABLESPACE blockts1;

表が作成されました。

SQL> INSERT INTO block1 VALUES (100, 'data1');

1行が作成されました。

SQL> COMMIT;

コミットが完了しました。
```

上記のCREATE文で作成されたテーブルは USER_TABLESビューだけでなくUSER_BLOCKCHAIN_TABLESビューに情報が格納されます。

```
SQL> SELECT * FROM user_blockchain_tables;

TABLE_NAME                     ROW_RETENTION ROW TABLE_INACTIVITY_RETENTION HASH_ALG
------------------------------ ------------- --- -------------------------- --------
BLOCK1                                    16 NO                           1 SHA2_512
```

Blockchain TableにはLONG, TIMESTAMP WITH TIME ZONE等、一部のデータ型は指定できません。

```
SQL> CREATE BLOCKCHAIN TABLE block3 (c1 LONG, c2 TIMESTAMP WITH TIME ZONE, c3 TIMESTAMP WITH LOCAL TIME ZONE)
  2    NO DROP UNTIL 1 DAYS IDLE
  3    NO DELETE UNTIL 16 DAYS AFTER INSERT
  4    HASHING USING sha2_512 VERSION v1
  5    TABLESPACE blockts1;
CREATE BLOCKCHAIN TABLE block3 (c1 LONG, c2 TIMESTAMP WITH TIME ZONE, c3 TIMESTAMP WITH LOCAL TIME ZONE)
*
行1でエラーが発生しました。:
ORA-05816: failed to create blockchain or immutable table
ORA-05730: data type not supported for blockchain or immutable table
```

NO DELETE UNTIL句に指定される日数は16日以上を指定する必要があります。

```
SQL> CREATE BLOCKCHAIN TABLE block2 (c1 NUMBER, c2 VARCHAR2(10))
  2        NO DROP UNTIL 1 DAYS IDLE
  3        NO DELETE UNTIL 15 DAYS AFTER INSERT
  4        HASHING USING sha2_512 VERSION v1
  5        TABLESPACE blockts1;
CREATE BLOCKCHAIN TABLE block2 (c1 NUMBER, c2 VARCHAR2(10))
*
行1でエラーが発生しました。:
ORA-05741: minimum retention time too low, should be at least 16 days
```

テーブルの削除可能期間を示すNO DROP句は初期化パラメーターblockchain_table_max_no_dropの影響を受けるようですが検証できていません。

行の削除制限を示すNO DELETE句にLOCKEDを指定すると行の削除設定を変更できなくなります。その場合USER_BLOCKCHAIN_TABLESビューのROW_RETENTION_LOCKED列にYESが出力されます。

```
SQL> CREATE BLOCKCHAIN TABLE block2 (c1 NUMBER, c2 VARCHAR2(10))
  2    NO DROP UNTIL 1 DAYS IDLE
  3    NO DELETE LOCKED
  4    HASHING USING sha2_512 VERSION v1
  5    TABLESPACE blockts1;

表が作成されました。

SQL> ALTER TABLE block2 NO DELETE UNTIL 18 DAYS AFTER INSERT;
ALTER TABLE block2 NO DELETE UNTIL 18 DAYS AFTER INSERT
*
行1でエラーが発生しました。:
ORA-05731: blockchain or immutable table BLOCK2 cannot be altered

SQL> SELECT * FROM user_blockchain_tables;

TABLE_NAME                     ROW_RETENTION ROW TABLE_INACTIVITY_RETENTION HASH_ALG
------------------------------ ------------- --- -------------------------- --------
BLOCK1                                    16 NO                           2 SHA2_512
BLOCK2                                       YES                          1 SHA2_512
```

# 列定義
各レコードの作成日時や制約を実装する情報はORABCTAB_で始まる名前の隠し列として定義されています（下記の表）。しかしUSER_TAB_COLUMNSビューからは参照できません。またSQL*PlusのSET COLINVISIBLE ONを実行しても表示されませんでした。

|列名|データ型|説明|
|:---|:---|:---|
|ORABCTAB_INST_ID$|NUMBER(22)|行がインサートされたインスタンスID|
|ORABCTAB_CHAIN_ID$|NUMBER(22)|チェーンID (0～31）|
|ORABCTAB_SEQ_NUM$|NUMBER(22)|チェーンのシーケンス番号|
|ORABCTAB_CREATION_TIME$|TIMESTAMP WITH TIME ZONE|レコード作成日時|
|ORABCTAB_USER_NUMBER$|NUMBER(22)|行を追加したユーザーID|
|ORABCTAB_HASH$|RAW(2000)|行のハッシュ値|
|ORABCTAB_SIGNATURE$|RAW(2000)|ハッシュ値から計算される行のシグネチャ|
|ORABCTAB_SIGNATURE_ALG$|NUMBER(22)|シグネチャ・アルゴリズム|
|ORABCTAB_SIGNATURE_CERT$|RAW(16)|署名された行の署名に関連付けられた証明書のGUID|
|ORABCTAB_SPARE$|RAW(2000)|将来のために予約|

```
SQL> SET COLINVISIBLE ON
SQL> DESC block1
 名前                                    NULL?    型
 ----------------------------------------- -------- ----------------------------
 C1                                                 NUMBER
 C2                                                 VARCHAR2(10)

SQL> SELECT c1, c2, ORABCTAB_SEQ_NUM$, ORABCTAB_CREATION_TIME$ FROM block1;

        C1 C2         ORABCTAB_SEQ_NUM$ ORABCTAB_CREATION_TIME$
---------- ---------- ----------------- ------------------------------------
       100 data1                      1 21-06-30 05:50:41.930720 +00:00
```