プログラミング
Commodore 64 BASIC for PostgreSQL
Commodore 64 Basic for PostgreSQL (thombrown.blogspot.com)
要約
この記事は、PostgreSQLの拡張機能であるPL/CBMBASICを紹介しています。これは、1982年当時のCommodore 64 BASIC V2インタプリタをPostgreSQLのバックエンドプロセス内で直接実行できるようにするものです。これにより、開発者はSQL関数内で懐かしのBASICコードを記述し、実行できるようになります。この拡張機能は、BASICの変数命名規則の制限や、ディスクドライブデバイス8へのアクセスを模倣したSQL実行機能などを提供します。
全文翻訳
LOAD "PL/CBMBASIC",8,1: PostgreSQLのためのCommodore 64 BASIC
リンクを取得 Facebook X Pinterest Email その他のアプリ
2026年7月3日
ある程度の年齢であれば、「38911 BASIC BYTES FREE」という言葉は、どんなセラピーでも癒せない何かをあなたにもたらすでしょう。青い画面を覚えていますか。雑誌から3ページにわたるリストを入力し、「?SYNTAX ERROR IN 2340」というエラーが出て、どのページにタイプミスがあったのか分からなかったことを覚えています。ディスクドライブがデバイス8であり、大陸の移動よりも遅かったことを覚えています。
私にはニュースがあります。それらのすべてが、今やPostgreSQLの中で実行されます。
PL/CBMBASICは、Commodore 64 BASIC V2上で関数本体を実行する手続き型言語拡張機能です。似せたものでも、トリビュートでもありません。1982年当時の実際のMicrosoft/Commodoreインタプリタが、Michael Steil氏のcbmbasicプロジェクトを通じて、6502 ROMをC言語に静的再コンパイルしたものです。そのC言語コードは拡張機能の共有ライブラリに直接コンパイルされるため、インタプリタはバックエンドプロセス内に存在します。すべての関数呼び出しは、インメモリでのパワーサイクルです。64KBのRAM配列をゼロにし、CPUレジスタをリセットし、ROMの$E394から再エントリーします。この一連の処理は、約15〜20マイクロ秒で完了します。これは、ハードウェアがかつて管理していた速度の約1000倍であり、大きなテーブルの各行に対して罪悪感を感じることなく呼び出すのに十分な速さです。
CREATE EXTENSION plcbmbasic;
CREATE FUNCTION hello(who text) RETURNS text AS $$
10 PRINT "HELLO, ";WHO$;"!"
$$ LANGUAGE plcbmbasic;
SELECT hello('WORLD'); -- HELLO, WORLD!
はい、これらは行番号です。はい、必須です。ユーザーコードは自然の摂理に従い、行10から始まります。なぜなら、0から9行は予約されているからです。拡張機能は、コードが実行される前に、関数の引数を通常のBASIC代入としてそこに注入します。whoという名前のテキストパラメータはWHO$として到着し、smallint型のlivesは本物の16ビットLIVES%になり、それ以外のすべての数値は40ビットCBM浮動小数点数(9桁の有効数字)として扱われます。
バリデーターには意見があります。なぜならBASIC V2には意見があったからです。
C64で1時間以上プログラミングした人なら誰でも、TOTALという名前の変数が使えないことに気づいたでしょう。トークナイザーはキーワードを識別子の途中でも圧縮するため、TOTALはTOを含んでしまい、ゴミになりました。SCOREはORを含んでいました。BUDGETはGETを含んでいました。名前の最初の2文字だけが重要だったので、USERNAMEとUSERIDは…まあ、それは大丈夫でしたが、ALPHAとALPSはサイレントに同じ文字列になりました。そしてTIとSTはシステムによって予約されていました。
この拡張機能はバリデーターを提供するため、PostgreSQLは実行時に再発見させるのではなく、CREATE FUNCTION時にこれらの意見を伝えます。
ERROR: parameter name "total" contains the BASIC keyword TO
HINT: This is why nobody could ever have a variable called TOTAL on the Commodore 64.
一部のトラウマは、最初に受けたものよりも良いエラーメッセージに値します。
OUTパラメータ、変数テーブルをたどる
BASICプログラムが終了すると、その変数はエミュレートされた64KBのRAM内に残っています。そのため、OUTおよびINOUTパラメータの場合、ハンドラは唯一合理的なことを行います。それは、VARTAB ($2D/$2E) と ARYTAB ($2F/$30) の間の7バイトエントリであるBASICの単純変数テーブルをたどり、型エンコードされた名前バイトをデコードし、5バイト浮動小数点数、16ビット整数、および文字列記述子をSQL値に変換します。
CREATE FUNCTION divmod(num int, den int, OUT quot int, OUT rmd int) AS $$
10 QUOT=INT(NUM/DEN)
20 RMD=NUM-QUOT*DEN
$$ LANGUAGE plcbmbasic;
SELECT * FROM divmod(47, 5); -- quot | rmd -- ------+----- -- 9 | 2
他のプロセスのメモリから結果をピーキングするのは、PostgreSQLのドキュメントで今後しばらく見かけるとは思えないパターンですが、ここでは非常に正しく感じられます。
データベースはデバイス8
これが私が最も満足している部分です。Commodore 64では、データはディスクドライブ(デバイス8)にあり、OPEN, INPUT#, GET#, PRINT#, CLOSE, そしてSTステータス変数を使ってそれに話しかけました。PL/CBM-BASICでは、デバイス8はデータベースです。OPENする「ファイル名」はSQLステートメントであり、トランザクション内でSPIを通じて実行されます。
CREATE FUNCTION top_scores() RETURNS text AS $$
10 OPEN 1,8,0,"SELECT NAME, SCORE FROM HISCORES ORDER BY SCORE DESC"
20 INPUT#1,N$,S
30 IF ST<>0 AND N$="" THEN 60
40 PRINT N$;" ";S
50 IF ST=0 THEN 20
60 CLOSE 1
$$ LANGUAGE plcbmbasic;
列値はCRで区切られたレコードごとに1つずつストリームバックされ、STは最後のバイトでEOFビット(64)を拾います。これは、1541から読み取ったときと同じ方法です。読み込み完了ループは、1985年に書いたものと変更なく動作します。行30で行っているように、空のファイルに注意する必要があった部分も含みます。
さらに良くなります。セカンダリアドレス15はドライブのコマンドチャネルでした。DOSコマンドをPRINT#し、00, OK,00,00という応答を読み取るのに使いました。これも動作します。
10 OPEN 15,8,15
20 PRINT#15,"DELETE FROM HISCORES WHERE SCORE < 1000"
30 INPUT#15,EN,EM$,RC,ES
ステータスレコードは、元の状態を尊重して0,OK,<行数>,0となります。各PRINT#は追記され、末尾のCRが実行されるため、BASICの255文字の文字列制限を超えるステートメントを、分割して送信することで構築できます。INSERT, UPDATE, DDLなど、何でも可能です。これはスーパーユーザーのみが利用できる信頼されていない言語なので、常にひどいことをする能力がありましたが、今ではFORループと小文字なしでそれを行うことができます。
実行時エラーは、Simons' BASICが使用したのと同じプラグインメカニズムである$0300のインタプリタ自身のERRORベクタを通じてトラップされ、間違いは実際のROMエラーコードを伝える正規のPostgreSQLエラーとして到着します。
ERROR: BASIC error: ?DIVISION BY ZERO ERROR IN 20
そして、KERNALのSTOPルーチン(RUN/STOPキーのスキャン、各ステートメントの前にポーリングされる)はCHECK_FOR_INTERRUPTS()にパッチされているため、不滅の10 GOTO 10はstatement_timeoutによってクリーンに終了します。RUN/STOPキーがついに確実に機能するようになりました。44年かかりました。
速いか?速さを定義する
私はPL/Pythonと比較して、同一の関数をベンチマークしました。PL/Pythonが勝ちます。これは予想通りです。インタプリタを温めたままにしておく言語ではなく、関数呼び出しごとにCommodore 64を再起動する言語ですから。単純な呼び出しでは約14〜19倍速く、関数内で100行をクエリするワークロードでは約6倍に縮まります。この場合、両方の側面で同じSPIコストがかかります。しかし、C64のフロアは15マイクロ秒のパワーサイクルであり、これは非インラインSQL関数と同じコスト帯に位置します。そしてインタプリタは、毎秒約100万BASICステートメントを処理します。このROMが出荷されたマシンは、約1000を管理していました。1982年の8ビットインタプリタが、呼び出しごとに完全なパワーオンリセットを実行しながら、CPythonに1桁半のオーダーで迫るというのは、誰も期待する権利がある以上の成果です。
注釈
内部は1982年であり、拡張機能はそのように振る舞います。すべて大文字で、文字列リテラルも含みます。なぜなら、C64のデフォルト文字セットには、まともな小文字がほとんどなかったからです。文字列は255文字で上限に達します。浮動小数点数は9桁の有効数字を持ちます。NULLはありません。なぜならNULLはまだ発明されていなかったからです。それは空文字列として現れ、気にするならクエリでCOALESCEを使用できます。INPUTはエラーを発生させます。なぜなら、データベースにキーボードが接続されていないからです。POKEとSYSは、危険を楽しむならエミュレートされた64KBに対して機能し、無謀なPOKEが最も悪くても、次の呼び出しのパワーサイクルまでマシンを混乱させるだけです。
コードはgithub.com/darkixion/pl-cbmbasicにあり、回帰テストスイートと、残りの注釈を含むREADMEがあります。スーパーユーザー権限が必要で、本番環境へのデプロイ…は選択肢であり、ノスタルジアは必須です。
READY. █
c64 cbmbasic postgresql
場所: Crawley, UK
リンクを取得 Facebook X Pinterest Email その他のアプリ
コメント
コメントを投稿
PostgreSQLドキュメント再刷新
2010年9月22日
オンラインのPostgreSQLドキュメントを定期的に参照している方は、メジャーリリース9.0に合わせて、ドキュメントが刷新されたことに気づいたかもしれません。もし気づいていなければ、見てみてください。これはPostgresコミュニティの多くの人々の意見を取り入れて、かなりの改訂を経てきました。すべてのものと同様に、すべての人を満足させることはできません。そして、これはそれほど真実ではありません。