[Oracle 23ai] SQL新機能：読み取り専用ユーザが作成可能に！

## 環境
・Oracle Database 23ai
　※DBエディションやOSによって差異はなし

## やれること
読み取りしかできないDBユーザを作成することができるようになりました。
データの変更・削除や、表の削除ができないため、安全にデータの参照をさせることができます。

DBユーザ自体を読み取り専用とすることもできますし、
通常は読み書き可能にしておいて、セッションを読み取り専用にすることも可能です。

なお、読み取り専用になるのは「そのDBユーザで接続したときの操作」です。
他の管理者権限をもったようなDBユーザから、読み取り専用DBユーザが所有するテーブルデータの操作は可能です。
そのため、「そのDBユーザで接続したときに誤ったことができないようにする」というのが主な目的になるかと思います。


## DBユーザを読み取り専用にする構文
:::note info
ALTER USER testuser READ ONLY;
:::

読み書き可能の戻す構文

:::note info
ALTER USER testuser READ WRITE;
:::


## 実行例

#### (1) DBユーザの作成（読み書き可能状態）
まずは 接続とテーブル作成のみ可能なDBユーザを作成してみます。
また、そのDBユーザの読み取り可否を確認します。
ディクショナリ「DBA_USERS」に新しい「READ_ONLY」列が追加されています。
YESの場合、読み取り専用ユーザになっています。デフォルトは読み書き可能のため、「NO」になります。

```
SQL> connect system/Password_1_2_3@db23
接続されました。

SQL> CREATE USER readtest IDENTIFIED BY oracle QUOTA unlimited ON users;

ユーザーが作成されました。

SQL> GRANT create session,create table TO readtest;

権限付与が成功しました。

SQL> SELECT username,created,read_only FROM dba_users WHERE username = 'READTEST' ORDER BY  username;

USERNAME                         CREATED  REA
-------------------------------- -------- ---
READTEST                         24-06-30 NO　　★NOのため読み書き可能状態です
```


#### (2) テストテーブルの作成
テスト用のテーブルを作成し、読み書き可能の動作を確認します。
システム権限「CREATE TABLE」が付与されていれば、TABLEに関する全権があるため
データのINSERT,UPDATE,DELETEも、テーブルのALTER,DROPも可能です。

```
SQL> connect readtest/oracle@db23
接続されました。
SQL> create table t1 ( id number(1) );

表が作成されました。

SQL> insert into t1 values(1);

1行が作成されました。

SQL> commit;

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

SQL> select * from t1;

        ID
----------
         1

SQL> update t1 set id = 2;

1行が更新されました。

SQL> delete t1;

1行が削除されました。

SQL> rollback;

ロールバックが完了しました。
```


#### (3) DBユーザを読み取り専用にする
DBユーザを読み取り専用にするには、ALTER USER文を使用します。
結果は「DBA_USERS」の「READ_ONLY」列で確認可能です。

```
SQL> connect system/Password_1_2_3@db23
接続されました。

SQL> alter user readtest read only;

ユーザーが変更されました。

SQL> SELECT username,created,read_only FROM dba_users WHERE username = 'READTEST' ORDER BY  username;

USERNAME                         CREATED  REA
-------------------------------- -------- ---
READTEST                         24-06-30 YES　　★YESのため読み取り専用状態です
```

#### (4) 読み取り専用ユーザで何ができるか確認する
DML文も、DDL文も、ORA-28194でエラーになります。

```
SQL> connect readtest/oracle@db23
接続されました。

SQL>  insert into t1 values(1);
 insert into t1 values(1)
             *
行1でエラーが発生しました。:
ORA-28194: 読取り操作のみを実行できます ヘルプ:
https://docs.oracle.com/error-help/db/ora-28194/


SQL> update t1 set id = 2;
update t1 set id = 2
*
行1でエラーが発生しました。:
ORA-28194: 読取り操作のみを実行できます ヘルプ:
https://docs.oracle.com/error-help/db/ora-28194/


SQL> delete t1;
delete t1
       *
行1でエラーが発生しました。:
ORA-28194: 読取り操作のみを実行できます ヘルプ:
https://docs.oracle.com/error-help/db/ora-28194/


SQL> create table t2 ( id number(1));
create table t2 ( id number(1))
*
行1でエラーが発生しました。:
ORA-28194: 読取り操作のみを実行できます ヘルプ:
https://docs.oracle.com/error-help/db/ora-28194/


SQL> alter table t1 modify (id number(2));
alter table t1 modify (id number(2))
*
行1でエラーが発生しました。:
ORA-28194: 読取り操作のみを実行できます ヘルプ:
https://docs.oracle.com/error-help/db/ora-28194/


SQL> drop table t1;
drop table t1
*
行1でエラーが発生しました。:
ORA-28194: 読取り操作のみを実行できます ヘルプ:
https://docs.oracle.com/error-help/db/ora-28194/


SQL> create sequence seq1;
create sequence seq1
*
行1でエラーが発生しました。:
ORA-28194: 読取り操作のみを実行できます ヘルプ:
https://docs.oracle.com/error-help/db/ora-28194/


SQL> create view v1 as select * from t1;
create view v1 as select * from t1
*
行1でエラーが発生しました。:
ORA-28194: 読取り操作のみを実行できます ヘルプ:
https://docs.oracle.com/error-help/db/ora-28194/

```

#### (5) 読み書き可能に戻す
読み取り専用ユーザが自分自身で読み書き可能にすることはできません。
他のDB管理ユーザで行う必要があります。

```
SQL> connect readtest/oracle@db23
接続されました。

SQL> alter user readtest read write;
alter user readtest read write
*
行1でエラーが発生しました。:
ORA-28194: 読取り操作のみを実行できます ヘルプ:
https://docs.oracle.com/error-help/db/ora-28194/
```

```
SQL> connect system/Password_1_2_3@db23
接続されました。

SQL> SELECT username,created,read_only FROM dba_users WHERE username = 'READTEST' ORDER BY  username;

USERNAME                         CREATED  REA
-------------------------------- -------- ---
READTEST                         24-06-30 YES

SQL> alter user readtest read write;
ユーザーが変更されました。

SQL> SELECT username,created,read_only FROM dba_users WHERE username = 'READTEST' ORDER BY  username;

USERNAME                         CREATED  REA
-------------------------------- -------- ---
READTEST                         24-06-30 NO

```