2025年1月10日金曜日

PL/SQLのコードをOracle SQL Developer Extension for VSCodeで開発する

オラクルはVSCodeの拡張機能として、2024年1月にOracle SQL Developer Extension for VSCodeをリリースしています。VSCode向けの、生成AIによるコード補完やコード生成を行う拡張機能が一般に利用可能になったこともあり、それらの機能を活用するためにPL/SQLのコードをVSCodeで開発する方法を確認してみます。

確認作業はOracleの開発ツールのプロダクト・マネージャのJeff Smithさんによる、以下のブログ記事に沿って行います。

PL/SQL debugger now available in SQL Developer for VS Code
https://www.thatjeffsmith.com/archive/2024/10/pl-sql-debugger-now-available-in-sql-developer-for-vs-code/

PLSQLを実行するデータベースとして、ローカルPCのコンテナで動作しているOracle Database 23ai Freeを使います。Autonomous DatabaseはパッケージDBMS_DEBUG_JDWPをサポートしていないため、Oracle SQL Developer Extension for VSCodeのPL/SQLデバッガは使えません。Oracle SQL Developerに含まれるデバッガであれば、Autonomous Databaseで利用できます。

Debugging your PL/SQL in Oracle Autonomous Databases
https://www.thatjeffsmith.com/archive/2021/02/debugging-your-pl-sql-in-oracle-autonomous-databases/

以下より実施した確認作業を紹介します。

Jeff Smithさんの記事に従って、以下のDEBUGGING_DEBUGGER.plsを作業に使用します。

オリジナルのコードはデータベースにサンプル・スキーマHRがインストールされていることを前提としたコードになっています。

本記事は、Oracle APEXのアプリケーションから呼び出すプロシージャ、ファンクションおよびパッケージを、VSCodeで作成することを想定しています。データベースでの作業は、APEXのワークスペース・スキーマに接続して作業します。そのため、スキーマHRが存在することを前提にできません。

代わりにAPEXのサンプル・データセットのHRデータを、APEXのワークスペースにインストールします。

作業対象のデータベースのAPEXのワークスペースにサインインし、SQLワークショップのユーティリティのサンプル・データセットを開きます。


サンプル・データセットに含まれるHRデータのインストールをクリックします。


言語は英語以外に選択肢はなく、スキーマはワークスペースのデフォルト・パーシング・スキーマが選ばれます。

通常は変更不要なので、そのまま次へ進みます。


データセットのインストールをクリックします。APEXのサンプル・データセットのHRデータは、オラクルがGitHubで公開しているHRサンプル・スキーマとほぼ同じですが、表名が競合しないように、表名の接頭辞としてOEHR_が付加されています。


サンプル・データセットがインストールされます。

アプリケーションは作成せず、終了をクリックします。


以上で作業に使用するスキーマの準備ができました。前掲のDEBUGGING_DEBUGGER.plsは、表HR.EMPLOYEES、HR.JOBSの代わりにOEHR_EMPLOYEES、OEHR_JOBSを参照するように変更済みです。

VSCodeを使う作業に移ります。

必ずしも必要な作業ではありませんが、PL/SQLコードを保持するリポジトリをGitHubに作成しました。リポジトリ名はdatabase-scriptsとしています。


ローカルの環境にクローンします。

git clone https://github.com/<username>/database-scripts.git

% git clone https://github.com/ujnak/database-scripts.git

Cloning into 'database-scripts'...

remote: Enumerating objects: 4, done.

remote: Counting objects: 100% (4/4), done.

remote: Compressing objects: 100% (4/4), done.

remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)

Receiving objects: 100% (4/4), done.

% 


VSCodeを起動します。Oracle SQL Developer Extension for VSCodeが未インストールであれば、拡張機能からインストールしておきます。


作成したディレクトリ(本記事ではdatabase-scripts)を開き、フォルダdebugger-testを作成します。その下にファイルDEBUGGING_DEBUGGER.plsを作成します。


ローカルのコンテナとして動作しているOracle Database 23ai Freeの環境に接続して作業を行います。こちらの記事の手順で作成した環境です。

おそらく、VSCodeとOracle Databaseの間でファイアウォールなどがなく、VSCodeからOracle Database(SQL*Netによる接続)、およびOracle DatabaseからVSCode(JDWP - Java Debug Wire Protocolによる接続)へTCPで接続可能なネットワーク環境であれば、同様に動作すると思われます。

拡張機能のSQL Developerを開いて、オラクル・データベースへの接続を作成します。


PL/SQLの開発作業は、APEXのワークスペース・スキーマで接続して実施します。PL/SQLデバッガを実行するために、ワークスペース・スキーマへの権限の割り当てと、JDWPによる接続を許可するためのネットワークACLの作成をSYSで行なう必要があります。

そのため、SYSによる接続を作成します。

接続名はlocal-23ai-freepdb1-sysとしました。ロールはSYSDBA、ユーザー名はsys、パスワードにはsysのパスワードを設定します。データベースへの接続時にパスワードの入力を省略するため、パスワードの保存をチェックしておきます。

接続タイプは基本、ホスト名はlocalhost、ポートは1521、タイプはサービス名、サービス名はfreepdb1になります。

上記の設定でテストを行い、問題がなければ保存します。


パスワードの保存が未チェックのときは、データベースへの接続を要求したときに、以下のようにパスワードの入力が求められます。


APEXのワークスペース・スキーマにPL/SQLデバッガを実行する権限を与えます。以下のコマンドを実行します。

grant debug connect session to <ワークスペース・スキーマ名>;

作成済みの接続local-23ai-freepdb1-sysをクリックしてデータベースに接続します。その接続のSQLワークシートを開きます。SQLワークシートに上記のコマンドを記述し、ボタン文の実行をクリックします。

SQLワークシート上でカーソルが割り当たっている文が実行されます。スクリプト出力にGrantが正常に実行されました。と表示されたらコマンドの実行は完了です。


APEXのワークスペース・スキーマによる接続を作成します。

接続名はlocal-23ai-freepdb1-wksp_apexdevとします。

接続先のデータベースは先ほどのSYSと同じです。接続ユーザーはAPEXのワークスペース・スキーマを指定します。APEXのワークスペース・スキーマはパスワードが未設定であったり、CREATE SESSIONまたはCONNECTロールが未割り当ての場合があります。あらかじめ、APEXのワークスペース・スキーマを接続ユーザーとして、データベースに接続できるかどうか確認し、不足があればAPEXのワークスペース・スキーマに追加で権限やロールを割り当てておきます。

今回の作業では、APEXのワークスペース・スキーマ(以下の設定ではユーザー名)としてWKSP_APEXDEVを指定しています。このスキーマは、サンプル・データセットのHRデータをインストールしたスキーマです。


作成した接続local-23ai-freepdb1-wksp_apexdevをクリックし、データベースに接続します。

作成済みのファイルDEBUGGING_DEBUGGER.plsを開きます。タイプarray_jobs、プロシージャdebugging_step_infoおよびdebugging_debuggerの3つを作成するため、これらの行を全て選択します。


スクリプトを表示している画面の右上にあるギアのアイコン(赤いアクセントが付いている方のアイコン)をクリックし、選択したスクリプトをデバッグ用にコンパイルします。スクリプトを実行する接続先の選択を求められたときは、APEXのワークスペース・スキーマへの接続であるlocal-23ai-freepdb1-wksp_apexdevを選択します。


スクリプトDEBUGGING_DEBUGGER.plsを実行すると、タイプARRAY_JOBS、プロシージャDEBUGGING_STEP_INTOおよびDEBUGGING_DEBUGGERが作成されます。

今までの作業で開いているファイルおよびSQLワークシートは、以降の作業では使用しません。一旦、これらのファイルをすべて閉じます。

接続local-23ai-freepdb1-wksp_apexdev(ローカルのコンテナで動作しているOracle Database 23ai FreeのPDB、FREEPDB1のスキーマWKSP_APEXDEV)にプロシージャDEBUGGING_DEBUGGERが作成されています。

このプロシージャを開きます。


プロシージャDEBUGGING_DEBUGGERが開いたら、右上の実行ボタンのデバッグを実行します。


デバッグを開始する画面が開きます。処理が実行される接続名(今回はlocal-23ai-freepdb1-wksp_apexdev)、ターゲット(今回はDEBUGGING_DEBUGGER)、それとプロシージャDEBUGGING_DEBUGGERに渡すパラメータXへの入力値が求められます。

デバッグをクリックするとデータベース・サーバーはVSCodeへ、JDWPによる接続を試みます。そのため、あらかじめネットワークACLによる許可が必要です。

ACLの表示をクリックすると、実行すべきコマンドが表示されます。


ACLの表示をクリックすると、IPアドレスの選択を求められます。データベース・サーバーから作業に使用しているVSCodeへの接続するためのIPアドレスになります。ホストとコンテナはネットワークが異なるため、ローカルホストの指定である127.0.0.1では接続できません。127.0.0.1でない方の接続先(以下の例では192.168.10.146)を選択します。


デバッグを実行するために必要なネットワークACLを追加するコードが表示されます。Copyをクリックし、クリップボードに保存します。


データベースにSYSで接続し、クリップボードにコピーしたネットワークACLを追加するコードを実行します。

接続local-23ai-freepdb1-sysを開き、その接続でSQLワークシートを開きます。SQLワークシートにクリップボードからネットワークACLを追加するコードをペーストし、ペーストした文を実行します。


スクリプト出力にPL/SQLプロシージャが正常に完了しました。と表示されれば、ネットワークACLの追加は完了です。


接続local-23ai-freepdb1-sysを閉じます。ネットワークACLが書かれているSQLワークシートも不要なので、タブを閉じておきます。保存は不要です。


DEBUGGING_DEBUGGER.runの画面に戻ります。すでに閉じている場合は、再度プロシージャDEBUGGING_DEBUGGERをデバッグ実行します。

パラメータXの入力値として5を設定します。

デバッグを実行する前にPL/SQLの表示をクリックし、プロシージャDEBUGGING_DEBUGGERのデバッグを行なうために実行されるPL/SQLコードを確認します。


プロシージャDEBUGGING_DEBUGGERを呼び出すコードとして、以下が表示されます。
-- runner for WKSP_APEXDEV.DEBUGGING_DEBUGGER
SET SERVEROUTPUT ON
DECLARE
  X NUMBER;
BEGIN
  X := 5;
  WKSP_APEXDEV.DEBUGGING_DEBUGGER(
    X => X);
  -- Rollback;
end;

SQLコードが確認できたら不要なタブなので、タブを閉じておきます。保存は不要です。


デバッグをクリックします。JDWPの接続先の選択を求められたときは、ネットワークACLとして追加した接続先を選択します。


プロシージャDEBUGGING_DEBUGGERに引数Xに5を与えた実行結果が、スクリプト出力に表示されます。

ブレークポイントが設定されていないため、デバッグ実行でもスクリプトの最後まで処理が実行されます。


プロシージャDEBUGGING_DEBUGGER.plsのタブに移り、ブレークポイントを設定します。

行番号の左隣をクリックすると赤いマークが付き、ブレークポイントとして設定されます。


タブDEBUGGING_DEBUGGER.runに移り、再度デバッグをクリックします。


今度は設定したブレークポイントの位置で、PL/SQLの処理が一時停止します。

左側には、一時停止した時点での変数の値、ウォッチ式、コールスタックといったスクリプトの実行状況が表示されます。


画面上部にデバッガの操作パネルが表示されています。

一番左の6個の点のアイコンを掴むと、操作パネルを移動できます。それ以外は左から、続行、ステップ・オーバー、ステップ・イン、ステップ・アウト、再起動、停止(または中断)になります。

この辺りの操作は、PL/SQLに限らず一般的なデバッガが持つ機能と同じです。


さて、以上でPL/SQLでのコードの記述やデバッグができるようになりました。

DEBUGGING_DEBUGGERのコードを修正します。以下の2行をプロシージャDEBUGGING_DEBUGGERの中間に挿入します。
 -- print how many lops we will do
 DBMS_OUTPUT.PUT_LINE('x is ' || x);
コードを挿入した後に、コンテキスト・メニューを表示してデバッグ用にコンパイルします。


プロシージャDEBUGGING_DEBUGGERをコンパイルした後、先ほどと同様にコードを実行します。プロシージャに挿入したコードが実行されていることが確認できます。


上記の変更はデータベースに保存されているプロシージャDEBUGGING_DEBUGGERを更新しています。記事の最初に作成したDEBUGGING_DEBUGGER.plsは更新されません。


パッケージ、プロシージャ、ファンクションといったPL/SQLで記述されたデータベースのオブジェクトは、コードがデータベースに保存されます。これらのコードをGitなどのリポジトリに保存する場合はファイルとして保存することになります。データベースに保存されるコードとGitに保存されるコードが自動的に同期されることはありません。

どのようなフローで同期させるかは、開発するアプリケーションの規模や開発チームの大きさで変わるように思います。アプリケーションや開発チームが小さければ、データベースに保存されているオブジェクトを直接編集し、編集が完了したコードをデータベースからGitに保存する方が手間も少なく開発速度も速いでしょう。反対にアプリケーションや開発チームが大きい場合は、勝手にデータベースのオブジェクトを変更されると大きな問題になりそうです。Gitなどを使って変更を管理し、テストやレビューを受けたコードよりデータベースのオブジェクトを作成し、直接データベースのオブジェクトを変更するのは禁止する、といった運用が妥当なように思います。

Oracle SQL Developer Extension for VSCodeのデバッガに関する設定は、設定のデバッガにあります。


全てJDWPでの接続に関する項目です。


今回の記事は以上になります。

余談

最近話題のAI Code EditorとしてCursorがあります。CursorはVSCodeをフォークして作られていて、VSCode用の拡張機能をサポートしています。

Oracle APEXのアプリケーション開発に使うには、フロントエンドの開発では拡張機能のLive Serverが必要です。バックエンドではOracle SQL Developer Extension for VSCodeが必要です。

この両方の拡張機能がCursorで使えるか確認してみました。

Cursor自体には、Live ServerおよびOracle SQL Developer Extension for VSCodeの両方とも組み込めています。


Live Serverは問題なく動作します。


Oracle SQL Developer Extension for VSCodeで問題なくデバッグも動きました。


CursorもVSCodeと同様に、Oracle APEXのアプリケーション開発に使用できるでしょう。

完

2025年1月9日木曜日

MotionのQuick Startを3つの異なる実装方法でAPEXアプリケーションに組み込んでみる

State of JavaScriptによる2024年のサーベイを見ていたところ、Graphics & Animationsの分野でFramer Motionが3位になっていました。Framer MotionはReact向けのライブラリなのでOracle APEXでは使えませんが、Motion自体はVanilla JavaScriptの環境に組み込めるため、Oracle APEXにも組み込むことができます。

実際にMotionのJavaScriptのQuick startをOracle APEXに実装してみました。Motionのサイトの以下のページに記載されています。

今回は単にMotionのQuick startをAPEXアプリケーションのページに実装するだけではなく、以下の3種類の方法で実装します。
  1. 外部ファイルに素のJavaScriptでコーディングする。
  2. 外部ファイルにapex.actionsを使ったコーディングをする。
  3. 外部ファイルを使わず、主に動的アクションで実装する。
APEXアプリケーションに組み込んだMotionのQuick startは以下のように動作します。上記の3種類とも、同じ動作になるように実装しています。


上記のAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-motion.zip

これより、それぞれの実装について簡単に紹介します。

素のJavaScriptによる実装


素のJavaScriptによる実装は、ページ番号1のホーム・ページに行っています。左ペインに現れるレンダリング・ビューに配置されているコンポーネントは概ねHTML要素に対応していて、APEXアプリケーションにJavaScriptのコードやCSSのクラス定義は含みません。

JavaScriptのコードは、ページ・プロパティのJavaScriptのファイルURLに記述している以下のファイルにまとめています。

[module,defer]#APP_FILES#js/quick-start-motion#MIN#.js


CSSのクラス定義は、ページ・プロパティのCSSのファイルURLに記述している以下のファイルにまとめています。

#APP_FILES#css/quick-start-motion#MIN#.css


画面に配置されるOracle APEXのコンポーネントは、コンポーネントの単位で静的IDとしてHTML要素のID属性を設定できます。そのため、コンポーネントに設定した静的IDをgetElementByIdの引数として渡すことにより、処理の対象とするHTML要素を取得できます。

以下の画面のように、ボタンに静的IDとしてANIMATE_ROTATEが設定されている場合、ボタン要素を取得するには以下を呼び出します。

document.getElementById("ANIMATE_ROTATE")


コンポーネントに含まれるHTML要素、例えばレポートに含まれるセルのようなHTML要素にアクセスする場合は、CSSクラスを設定してquerySelectorまたはquerySelectorAllを呼び出して、対象とするHTML要素を取り出します。CSSクラスといってもquerySelectorなどの引数に与えるための名前で、実際にCSSクラスを定義する必要はありません。CSSクラスを設定する場所が列CSSクラス、行CSSクラス、外観のCSSクラス、詳細のCSSクラスのどこであっても、HTML要素のclass属性に含まれるため、.クラス名 (ドットで始まるクラス名)をセレクタとして指定してコンポーネントの内部にあるHTML要素にアクセスできます。

アニメーションの開始および終了は、それぞれのボタンをクリックすることで処理を呼び出します。ボタンへのイベント・リスナーの登録は、ボタン要素を取得して、addEventListenerを呼び出してコールバック・ファンクションを設定しています。
document.getElementById('ANIMATE_ROTATE').addEventListener('click', (event) => {
    animateRotate = animate(
        ".box",
        { 
            rotate: [ 0, 360 ]
        },
        {
            duration: 1,
            repeat: 3
        }
    );
    animateRotate.then(() => {
        apex.debug.info('rotate is completed.');
    });
    apex.debug.info('rotate is started.');
});
このようなコーディングは開発者への負担が大きいため、Oracle APEXのようなローコード開発プラットフォームが使われるようになったと言えますが、生成AIによるコード生成を前提とすると、より一般的な形式のコードを出力させた方が効率が良さそうです。

Oracle APEXのアプリケーションについては、コンポーネントへ静的IDやCSSクラスを設定することが多くなります。


apex.actionsを使った実装



ページ番号2に、イベント・リスナーを登録する代わりに、Oracle APEXが提供しているapex.actionsを使った実装を行っています。ボタンやリンクをクリックしたときに、apex.actionsとして設定したアクションを呼び出しています。

動作は素のJavaScriptとまったく同じですが、apex.actionsを使って、コードを以下のように書き換えています。


いくつかの面でapex.actionsによる実装は、イベント・リスナーの設定よりも分かりやすい面があります。
  1. イベントの伝搬を意識しなくてよい。
  2. 呼び出される処理に名前が付いている。
  3. アクションを登録するコンテキストごとに名前空間が分かれる。
しかし、apex.actionsはボタンのクリックかリンクのクリックでの呼び出しに限定されるため、例えばmouseenterやmouseleaveといったイベントに対する処理を設定するには、イベント・リスナーを設定する必要があります。

apex.actionsを使う場合は、コンテキストの作成対象となるリージョンに静的IDを設定します。


処理を呼び出すボタンにカスタム属性data-actionを設定してアクション名を指定するか、リンクの場合はhref属性に[context-id]action-name?argumentsの形式でアクション名や引数を指定します。



動的アクションによる実装



ページ番号3に、Oracle APEXでの一般的な実装方法となる、動的アクションを使った実装を行なっています。

ひとつひとつのボタンに、JavaScriptコードを実行する動的アクションを設定しています。


値の設定、表示、非表示といった宣言的な設定だけで済む動的アクションであれば、処理内容を把握するのも難しくないと思います。しかし、JavaScriptコードがそれぞれの動的アクションに設定されている場合は、全体の処理を把握するのが難しくなる傾向があります。

動的アクションの間で共有する変数やファンクションは、ページ・プロパティのJavaScriptのファンクションおよびグローバル変数の宣言に記述する必要があります。
var animateRotate = null;
var animateThree = null;
var animateBasic = null;
var animateSpring = null;
var animateStagger = null;

var cube;

function rad(degrees) {
    return degrees * (Math.PI / 180)
};
Motionについては、ライブラリをJavaScriptのファイルURLに指定して読み込めます。ページ中からは、グローバル変数Motionより機能を呼び出せます。

https://cdn.jsdelivr.net/npm/motion@11.16.0/dist/motion.min.js

対してThreeJSはESモジュールとして読み込む必要があり、また、従属しているライブラリもあるため、importmapの設定が必要です。
<script type="importmap">
    {
        "imports": {
            "three": "https://cdn.jsdelivr.net/npm/three@0.172.0/build/three.module.min.js",
            "three/webgpu": "https://cdn.jsdelivr.net/npm/three@0.172.0/build/three.webgpu.min.js"
        }
    }
</script>

また、アニメーションについては、静的コンテンツのリージョンにインラインでコーディングする必要があります。


3種類の実装の紹介は以上になります。

実はOracle APEXはjQueryを使っているため、どのようなページでもjQueryがロードされ、呼び出すことができます。

https://docs.oracle.com/en/database/oracle/apex/24.1/aexjs/

The jQuery library is used by APEX and is always loaded on every page. It can be used by your code.

そのため、jQueryを使ったコーディングも可能です。今回の記事でjQueryを取り上げなかったのは、個人的にjQueryは使わないようにしているためで、jQueryを使うことに問題があるわけではありません。そのため、jQueryを使うという選択肢もあります。

今回の記事は以上になります。

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

完

アプリケーションに与えたSELECT文を実行して動的にクラシック・レポートを表示する

SELECT文をテキスト領域のページ・アイテムに入力し、実行した結果をクラシック・レポートに表示してみます。主にDBMS_SQL.PARSEとDBMS_SQL.DESCRIBE_COLUMNSを呼び出します。

Oracle APEXのレポートやチャートのソースとなる表やビューまたはSELECT文は、アプリケーション開発時に解析され、見つかった検索対象の列がレポートに設定されます。そのため、ソースのタイプとしてSQL問合せを返すファンクション本体を選択し、SELECT文をアプリケーションの実行時に決定する場合に検索列の順番や数を変更できません。例外として、クラシック・レポートには汎用列名の使用という設定があり、レポートに列のメタデータを設定しない代わりに、検索対象の列を変更することができます。汎用列を使用した場合、列名はCOL01、COL02、COL03、...といった連番が付いた名前になり、汎用列数として設定した数だけ、あらかじめクラシック・レポートに列が定義されます。

今回の記事では、以下のAPEXアプリケーションを作成します。入力したSELECT文の結果をクラシック・レポートに表示します。入力したSELECT文の列定義は、パッケージDBMS_SQLを使って取り出します。


アプリケーションの名前をDynamic SQL Reportとして、空のAPEXアプリケーションを作ります。デフォルトで作成されるホーム・ページにクラシック・レポートを実装します。

ボタンSUBMITはページの送信を行なうだけで、個別のプロセスを呼び出したりはしません。SELECT文を入力したページ・アイテムP1_SELECTの内容をセッション・ステートに保存し、クラシック・レポートのソース内で参照できるようにします。


SELECT文を入力するページ・アイテムをP1_SELECTとして作成します。タイプはテキスト領域です。入力したSELECT文をセッション・ステートに保存するため、セッション・ステートのデータ型としてVARCHAR2、ストレージにセッションごと(永続)を設定します。


リージョンを作成し、タイプをクラシック・レポートとします。

ソースのタイプとしてSQL問合せを返すファンクション本体を選択し、SQL問合せを戻すPL/SQLファンクション本体に以下を記述します。

汎用列名の使用をオンにし、汎用列数は10とします。汎用列数は必要に応じて変更します。


クラシック・レポートの属性を開きます。

メッセージのデータが見つからない場合に、データが見つかりません。と記述します。

ヘッダーのタイプとしてPL/SQLファンクション本体を選択し、PL/SQLファンクション本体に、列名を : (コロン)で連結した文字列を返すPL/SQLコードを記述します。



以上でアプリケーションは完成です。アプリケーションを実行すると、記事の先頭のGIF動画のように動作します。

今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/dynamic-sql-report.zip

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

余談

VSCodeの拡張機能ClineがPL/SQLを書いてくれるか試してみました。APIプロバイダはローカルで実行しているOllama、モデルとしてhhao/qwen2.5-coder-tools:32bを使っています。Macbook Pro M4の128GBメモリのマシンで実行しています。

% ollama ps

NAME                            ID              SIZE     PROCESSOR    UNTIL              

hhao/qwen2.5-coder-tools:32b    5d17b48771de    43 GB    100% GPU     3 minutes from now    

%


タスクの最初のプロンプトとして、以下を与えています。
Please write a PL/SQL code to retrieve column definition of given select statement by using DBMS_SQL package. input is string that is for SELECT statement and the output is the columns and data types found in select statement in the array.

例外処理が含まれていなかったので、以下のプロンプトを与えました。

please add an exception hander when wrong sql is provided.
作成されたファイルget_column_definitions.sqlをAcceptすると、以下のコマンドを実行して、と案内されました。Run Commandというボタンが表示されたのでクリックすると、VSCodeでターミナルが開いて、コマンドが実行されました。ユーザー名やパスワードが正しく無いので、エラーが発生しました。
sqlplus username/password@database @get_column_definitions.sql "SELECT * FROM your_table"
ユーザー名、パスワードを変更して実行するとcol_type_nameが無いというエラーが発生しました。以下のプロンプトを与えて、修正を要求しました。
pls-00302 has raised. it seems taht col_type_name is not exist . please fix.

col_type_nameとなっていた部分がcol_typeを使うように書き換わり、 col_typeの数値を型名に置き換えるコードが挿入されました。

上記のコードを実行する前に、先頭行にset serveroutput onを記述するように要求しました。

please put "set serveroutput on" as the first line of the script
以上で出来上がったコードがこちら。きちんと動きます。



ローカルのOllamaなので相当遅いですが、動くコードが生成されるのだからすごいものです。

完

2025年1月7日火曜日

GitHub PagesからOracle APEXのアプリの静的アプリケーション・ファイルを配信する

以前の記事「LottieのアニメーションをOracle APEXのアプリケーションに表示する」で作成したAPEXアプリケーションに含まれる静的アプリケーションファイルを、GitHub Pagesから配信するように設定します。

GitHub Pagesを使用するための設定については、色々なサイトで紹介されている記事を参照することをお勧めします。作業の参考になるように、GitHub側で実施した作業について簡単に紹介します。

最初にWebサイト名と同じ名前になるリポジトリ<username>.github.ioを作成しました。<username>の部分は、GitHubのユーザー名です。本記事ではリポジトリとしてujnak.github.ioを作成しました。GitHub PagesのWebサイト名は<username>.github.ioになります。Webサイト名と同名のリポジトリに保存されているデータはhttps://<username>.github.io/の直下から参照できるようになります。

GitHubのRepositoriesの画面より、新規にリポジトリを作成します。


Repository nameに<username>.github.ioを設定します。Descriptionには簡単な説明として「GitHub Pages for APEX Static Application Files」を記述しました。保護についてはPublicを選択します。

以上でCreate repositoryを実行します。


リポジトリが作成され、この後に実施すべき作業が表示されます。


手元のPCでの作業に移ります。

作成したリポジトリをクローンします。

git clone https://github.com/<username>/<username>.github.io.git

実行ディレクトリの下にディレクトリ<username>.github.ioが作成されます。

% git clone https://github.com/ujnak/ujnak.github.io.git

% ls

apexapps ujnak.github.io

% 


Lottieのアニメーションを表示するAPEXアプリケーションをアプリケーション・ビルダーで開き、共有コンポーネントの静的アプリケーション・ファイルを開きます。

Zipとしてダウンロードをクリックし、保存されているすべての静的アプリケーション・ファイルをダウンロードします。


ZIPファイルはf<アプリケーションID>_static_application_files.zipとしてダウンロードされます。

ダウンロードした静的アプリケーション・ファイルをリポジトリ<username>.github.ioにplay-lottieというディレクトリを作成し、その下に解凍します。

cd ujnak.github.io
unzip -d play-lottie ~/Downloads/f224_static_application_files.zip


% cd ujnak.github.io

ujnak.github.io % unzip -d play-lottie ~/Downloads/f224_static_application_files.zip

Archive:  /Downloads/f224_static_application_files.zip

Implementation by Anton Scheffer

  inflating: play-lottie/MyFirstLottie.json  

  inflating: play-lottie/MyFirstLottie.lottie  

  inflating: play-lottie/icons/app-icon-144-rounded.png  

  inflating: play-lottie/icons/app-icon-192.png  

  inflating: play-lottie/icons/app-icon-256-rounded.png  

 extracting: play-lottie/icons/app-icon-32.png  

  inflating: play-lottie/icons/app-icon-512.png  

  inflating: play-lottie/js/app-dotlottie.js  

  inflating: play-lottie/js/app-dotlottie.min.js  

  inflating: play-lottie/js/app-lottie.js  

  inflating: play-lottie/js/app-lottie.min.js  

ujnak.github.io % 


VSCodeのLive Serverを起動するため、<username>.github.ioの直下にファイルindex.htmlを作成します。以下のコマンドを実行し、最低限のHTMLを記述します。

echo "<html><body>Hosting Available</body></html>" > index.html

ujnak.github.io % echo "<html><body>Hosting Available</body></html>" > index.html

ujnak.github.io % 


今までに作成したファイルをコミットし、リポジトリにプッシュします。

git add .
git commit -m 'Add Static Files for Play Lottie'
git branch -M main
git push -u origin main

ujnak.github.io % git add .

ujnak.github.io % git commit -m 'Add Static Files for Play Lottie'

[main (root-commit) 45a16c0] Add Static Files for Play Lottie

 12 files changed, 128 insertions(+)

 create mode 100644 index.html

 create mode 100644 play-lottie/MyFirstLottie.json

 create mode 100644 play-lottie/MyFirstLottie.lottie

 create mode 100644 play-lottie/icons/app-icon-144-rounded.png

 create mode 100644 play-lottie/icons/app-icon-192.png

 create mode 100644 play-lottie/icons/app-icon-256-rounded.png

 create mode 100644 play-lottie/icons/app-icon-32.png

 create mode 100644 play-lottie/icons/app-icon-512.png

 create mode 100644 play-lottie/js/app-dotlottie.js

 create mode 100644 play-lottie/js/app-dotlottie.min.js

 create mode 100644 play-lottie/js/app-lottie.js

 create mode 100644 play-lottie/js/app-lottie.min.js

ujnak.github.io % git branch -M main

ynakakoshi@Ns-Macbook ujnak.github.io % git push -u origin main

Enumerating objects: 17, done.

Counting objects: 100% (17/17), done.

Delta compression using up to 16 threads

Compressing objects: 100% (16/16), done.

Writing objects: 100% (17/17), 37.45 KiB | 18.72 MiB/s, done.

Total 17 (delta 2), reused 0 (delta 0), pack-reused 0

remote: Resolving deltas: 100% (2/2), done.

To https://github.com/ujnak/ujnak.github.io.git

 * [new branch]      main -> main

branch 'main' set up to track 'origin/main'.

ujnak.github.io % 


どこかのタイミングでリモート・リポジトリの認証を要求されるかもしれません。今回の作業ではGitHub CLIのgh auth loginを実行し、認証しています。

以上でGitHub Pagesより、APEXの静的アプリケーション・ファイルが配信されるようになりました。index.htmlにアクセスして確認します。

https://<username>.github.io/index.html

先ほどindex.htmlに書き込んだHosting Availableの表示が確認できます。


VSCodeを起動し、ローカルのリポジトリ<username>.github.ioを開きます。

index.htmlを選択し、Live Serverを起動します。


Live Serverでは以下のURLより、index.htmlをアクセスできます。

http://localhost:5500/index.html


GitHub Pagesを静的アプリケーション・ファイルの参照先に変更します。

アプリケーション定義のユーザー・インターフェースの詳細にある、#APP_FILES#のパスとして以下を設定します。

https://<username>.github.io/play-lottie/


APEXアプリケーションを実行し、GitHub Pagesが静的アプリケーション・ファイルの参照先となっているか確認します。

JavaScriptコンソールのネットワークを開きます。

lottie-webのページでは、JavaScriptのファイルURLとして以下が設定されています。

[module, defer]#APP_FILES#js/app-lottie#MIN#.js

#APP_FILES#としてhttps://<username>.github.io/play-lottie/を設定しているため、ページが実行されたときにロードされるJavaScriptのファイルは以下になります。

https://<username>.github.io/play-lottie/js/app-lottie.js

置換文字列#MIN#は、開発モードおよびデバッグが有効な場合は空白に置換されます。プロダクションでは.minに置き換わります。

JavaScriptコンソールよりapp-lottie.jsを選択し、リクエストURLとしてGitHub Pagesのファイルを参照していることを確認します。


以上で静的アプリケーション・ファイルの参照先を、データベースからGitHub Pagesに移行することができました。この後はAPEXアプリケーションに保存されている静的アプリケーション・ファイルが参照されることはないため、すべて削除することもできます。

データベースを静的なファイルを配信するために使用するかわりに、コンテンツの配信を行なうサービスを使用する方がコストメリットがあります。ただし、静的なファイルはブラウザでキャッシュされるため、どの程度データベースから負荷をオフロードできるかはアプリケーションに依存します。

この構成でAPEXアプリケーションを開発する場合、静的アプリケーション・ファイルの変更はVSCodeで実施することになります。動作の確認にはセッション・オーバーライドを使用して、Live Serverよりローカルのファイルを参照します。

開発者ツールバーよりセッション・オーバーライドを開き、セッション・オーバーライドの有効化をオンにし、ファイル・パスのアプリケーション・ファイル#APP_FILES#として以下を設定します。

http://localhost:5500/play-lottie/

JavaScriptコンソールでファイルapp-lotttie.jsのリクエストURLが、Live Serverを指していることを確認します。


VSCodeよりファイルapp-lottie.jsを変更します。変更をJavaScriptコンソールから確認できるように、以下の1行を挿入します。

console.log('lottie-web is loaded.');


セッション・オーバーライドを使ってローカルのLive Serverを参照している場合は、上記の変更はページを再ロードすると即座に反映されます。


セッション・オーバーライドを解除するとGitHub Pagesを参照するため、先ほどの変更が行われる前のファイルが参照されます。そのため、追加したconsole.logによる出力は、JavaScriptコンソールに表示されません。


変更をGitHub Pages、つまりリモート・リポジトリに反映させるため、app-lottie.jsの変更をステージし、コミットしてプッシュを呼び出します。


セッション・オーバーライドを外し、キャッシュをリフレッシュする形でアプリケーションを再ロードすると、GitHub Pagesから参照しているapp-lottie.jsに変更が反映されていることが確認できます。


この状態でAPEXアプリケーションをリリースしても、プロダクションに変更は反映されません。プロダクション環境では置換文字列#MIN#が.minに置き換わり、app-lottie.min.jsを参照されるためです。

Oracle APEXの静的アプリケーション・ファイルとして保存される.jsファイルおよび.cssファイルは、スクリプト・エディタでの保存時に自動的にミニファイされます。VSCodeでは拡張機能を使うなどして、VSCode側でミニファイする必要があります。

例えばHookyQRのMinifyといった拡張機能を使用して、ミニファイします。


ミニファイしたファイルの変更をステージし、リモート・リポジトリにコミットとプッシュすることにより、プロダクションに変更が反映されます。


以上でプロダクションのアプリケーションにJavaScriptの変更が反映されました。


今回の記事は以上になります。

最近、制限はありますがVSCodeで無料でGitHub Copilotが使用できるようになりました。

英国在住の著名なAPEX開発者であるMatt Mulvaneyさんが早速、GitHub CopilotのFreeプランを使用した記事を公開しています。PL/SQLのコーディングを対象としています。

VSCode & Copilot Free for PL/SQL

JavaScript、CSS(APEXでは使わないがPython)などは生成AIが得意な言語なので、APEXのアプリケーション開発もVSCode + CopilotやCursorといったエディタを使うケースが多くなるかもしれません。

完

Canvaで作成したプレゼンテーションをAPEXのアプリケーションに埋め込む

Canvaで作成したプレゼンテーションをOracle APEXのアプリケーションに埋め込んでみます。Canvaでは作成したデザインを他のWebページに埋め込むためのスニペットを生成してくれるため、Oracle APEXのアプリケーションへ容易に埋め込めます。

Canvaでの作業はオンライン・ドキュメントの以下のセクションで説明されています。

デザインの埋め込みと埋め込みの非公開化

以下のように、APEXアプリケーションにCanvaで作成したプレゼンテーションを埋め込みます。


以下にCanvaのプレゼンテーションの埋め込み手順を紹介します。

最初にCanvaで埋め込むスニペットを生成します。

画面左上の共有をクリックし、埋め込みを探します。表示されていない場合は、すべて表示をクリックします。


共有の埋め込みをクリックします。


埋め込みをクリックし、スニペットを生成します。


Oracle APEXのアプリケーションへの埋め込みでは、HTML埋め込みコードの方を使用します。こちらのコードをコピーします。


Oracle APEXへの埋め込みにはタイプが静的コンテンツのリージョンを使用します。

Oracle APEXのページにリージョンを作成し、タイプを静的コンテンツとします。ソースのHTMLコードに、さきほどCanvaよりコピーしたHTML埋め込みコードをそのままペーストします。

通常は装飾は不要なので、外観のテンプレートにはBlank with Attributes (No Grid)を選択します。


以上でCanvaで作成したプレゼンテーションの埋め込みは完了です。ページを実行すると、以下のように表示されます。


埋め込んだプレゼンテーションは、親要素である静的コンテンツのリージョンの幅に合わせてスケールします。

例えば、レイアウトの列を6、列スパンを3とします。


埋め込んだプレゼンテーションは6番目の列から開始し、列幅が3になります。そのレイアウトに合わせて、Canvaのプレゼンテーションが縮小されて表示されます(以下のスクリーンショットでは、開発者ツールバーより、レイアウト列の表示を有効にしています)。


共有を停止する場合は、Canvaの画面から埋め込みリンクを削除します。


埋め込みリンクが削除されると、Oracle APEXの静的コンテンツの領域にForbidden (403)と表示されます。


Canva側で再度HTML埋め込みコードを生成すると、埋め込み元として新たなリンクが作成されます。そのため、Canvaのプレゼンテーションを表示するには、APEXの静的コンテンツのソースを更新する必要があります。

Canvaで作成したプレゼンテーションを、Oracle APEXのアプリケーションに埋め込む手順の紹介は以上です。

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

完