2021年7月19日月曜日

Oracle APEXによるSQLの実行

 Oracle APEXがSQLを実行する際の権限について確認しました。

最初に前提となる構成について説明します。前提を紹介したのち、パッケージDBMS_SYS_SQLを使用したSQLの実行について説明します。


ワークスペースへのスキーマの割り当て


Oracle APEXのワークスペースとデータベースのスキーマは、同じ名前で1対1に対応させている場合が多いと思います。実際にはワークスペースと異なる名前のデータベース・スキーマを割り当てたり、複数のデータベース・スキーマをワークスペースに割り当てることができます。

Oracle APEXの管理アプリケーションにサインインし、ワークスペースの管理を実行します。

ワークスペースとスキーマの割当ての管理を開きます。

ワークスペースと割当済みのスキーマの一覧が表示されます。ワークスペースAPEXDEVにスキーマAPEXDEVとAPEXDEV2が割り当て済みです。

割り当てを追加するには、スキーマの追加を実行します。

例えばワークスペースAPEXDEVに、新規にスキーマAPEXDEV3を作成した上で割り当てる手順は次のようになります。スキーマの追加をクリックします。

スキーマの選択で新規を選びます。へ進みます。

スキーマを新規に割り当てるワークスペースを選択します。今回の例ではAPEXDEVを選びます。へ進みます。

スキーマの作成に必要な情報を入力します。今回はスキーマとして、APEXDEV3パスワードに適当に設定、デフォルトの表領域USERS一時表領域TEMPとしています。へ進みます。


余談ですが、ウィザードによってワークスペースを作成する場合、表領域を新規に作成することができます。この場合、スキーマ毎に表領域が新規に作成されます。表領域を沢山作るとそれだけ監視対象が増えますし、経験上、表領域不足でシステムが停止することは多いです。ある程度大きい表領域をあらかじめ作成しておき、スキーマごとには作らない方が良いでしょう。

確認画面が表示されるので、スキーマの追加を実行します。


スキーマの割当ての一覧に表示されます。


ワークスペースAPEXDEVに3つのスキーマAPEXDEV、APEXDEV2、APEXDEV3が追加されています。

割り当てられたスキーマの確認


SQLワークスペースSQLコマンドより、割り当てられたスキーマを確認します。ワークスペースAPEXDEVにサインインし、SQLコマンドを開きます。左上のスキーマより、割当済みの3つのスキーマを選択できます。


スキーマAPEXDEVには英語の情報を投入した表EMP、スキーマAPEXDEV2には日本語の情報を投入した表EMPを作成しておきました。スキーマAPEXDEV3に表はありません。

最初にセッションの情報を確認します。以下のSQLを実行します。(このSQLはoracle-base.comのProxy User Authentication and Connect Through in Oracle Databasesから引用しています。)

select
sys_context('userenv','session_user') as session_user,
sys_context('userenv','session_schema') as session_schema,
sys_context('userenv','current_schema') as current_schema,
sys_context('userenv','proxy_user') as proxy_user
from dual;

スキーマAPEXDEVを選択して実行すると、以下の結果になりました。

SESSION_USERSESSION_SCHEMACURRENT_SCHEMAPROXY_USER
APEX_PUBLIC_USER-APEXDEV-

スキーマAPEXDEV2を選ぶとCURRENT_SCHEMAはAPEXDEV2になります。スキーマAPEXDEV3ではCURRENT_SCHEMAはAPEXDEV3です。

SESSION_USERはOracle REST Data Servicesが接続に使用しているユーザーです。PROXY_USERの設定はないので、プロキシ接続ではありません。Oracle APEXでのSQLの実行は、SESSION_USER(つまりAPEX_PUBLIC_USER)に関わらず、スキーマとして選択したユーザーで接続して実行しているのと同じ結果になります

スキーマAPEXDEVを選んでselect * from empを実行すると、内容が一覧されます。


スキーマAPEXDEV2を選んでselect * from empを実行すると、APEXDEV2にある表EMPの内容がリストされます。


スキーマAPEXDEV2よりAPEXDEVの表EMPを検索すると、以下のエラーが発生します。

ORA-00942: 表またはビューが存在しません。


これはスキーマとして指定したAPEXDEV2は、スキーマAPEXDEVの表をSELECTする権限がを持っていないためです。


アプリケーションへのスキーマの割当て


アプリケーション定義セキュティを開いて、データベース・セッションのセクションに含まれる解析対象スキーマとして、スキーマを割り当てます。

アプリケーションはここで指定されたスキーマの権限(ここで指定したスキーマで接続しているかのように)で実行されます。

レポート、チャートその他のソースとして表の所有者を選択できることがあります。大抵はParsing Schema(解析対象スキーマのことです)を選択していると思います。

この表の所有者の指定は解析対象スキーマの指定とは異なり、この所有者の権限で表にアクセスされるわけではありません。以下と同様に、カレント・スキーマが変更されます。

alter session set current_schema = 表の所有者

そのため、解析対象スキーマがAPEXDEVであれば、APEXDEVがAPEXDEV2(表の所有者)の表EMPのオブジェクト権限を持っていないとアクセスできません。


Oracle APEXでのSQLの実行


Oracle APEXでのSQLの実行については、マニュアルにほんの少しだけ記載があります。

アプリケーション・ビルダー・ユーザー・ガイド

22.4 データベース・レポートの使用

Oracle Application Expressは、Application ExpressエンジンをコールするAPEX_PUBLIC_USERとして、データベース・プールから物理的な接続を確立します。Application Expressエンジンは、別のユーザーである解析対象スキーマとして、SYS.DBMS_SYS_SQLを使用してSQLを解析します

 Oracle REST Data ServicesからAPEX_PUBLIC_USERとして接続し、SQLを実行する擬似的なコードは以下になります。

set serveroutput on

declare

    l_cursor integer;

    l_sql varchar2(4000);

    l_ignore integer;

    l_ret number;

    l_userid number;

    v_ename varchar2(200);

begin

    l_cursor := dbms_sql.open_cursor;


    -- 実行するSELECT文を設定。 

    l_sql := q'~select ename from emp~';

    -- ユーザーAPEXDEVのユーザーIDを取得する。

    select user_id into l_userid 

    from all_users where username = 'APEXDEV';


    -- DBMS_SYS_SQLの呼び出し。useridを指定する。

    sys.dbms_sys_sql.parse_as_user(

        c => l_cursor

        , statement => l_sql

        , language_flag => DBMS_SQL.NATIVE

        , userid => l_userid

        , schema => 'APEXDEV'

    );


    -- カーソルから結果を取り出す。

    dbms_sql.define_column(

        c => l_cursor

        , position => 1

        , column => v_ename

        , column_size => 200);

    l_ret := dbms_sql.execute(c => l_cursor);

    loop

        if dbms_sql.fetch_rows(l_cursor) > 0 then

            dbms_sql.column_value(

                c => l_cursor

                , position => 1 

                , value => v_ename);

            dbms_output.put_line(v_ename);

        else

            exit;

        end if;

    end loop;

    dbms_sql.close_cursor(c => l_cursor);

end;

/

プロシージャDBMS_SYS_SQL.PARSE_AS_USERを呼び出しています。実際の呼び出しでは、他のパッケージを経由して間接的に呼び出しています。

実行結果は以下のようになります。

KING

BLAKE

CLARK

JONES

SCOTT

FORD

SMITH

ALLEN

WARD

MARTIN

TURNER

ADAMS

JAMES

MILLER


PL/SQL procedure successfully completed.

Oracle APEXでのSQLの実行方法についての説明は以上です。簡単にまとめると、接続方法はどうあれ、Oracle APEXのアプリケーションは解析対象スキーマとして指定したスキーマの権限で実行される、ということになります。

Oracle APEXのアプリケーション作成の参考になれば幸いです。