PostgreSQL加载C64 BASIC扩展 老派BASIC兼容新数据库
速览
PostgreSQL全球开发者组近日在官方网站planet.postgresql.org上发布新扩展PL/CBMBASIC,用户可通过LOAD命令将C64 BASIC加载至PostgreSQL环境,实现经典的老式BASIC编程风格。这项扩展由Thom Brown贡献,旨在让熟悉C64 BASIC的用户无需切换语言就能继续在PostgreSQL上开发数据库应用。 这项举措意义重大,不仅丰富了PostgreSQL的生态选择,也为复古计算爱好者提供了现代数据库的编程入口,开启了跨时代技术融合的新可能。BASIC作为80年代经典语言,其简单易学的特点在当代仍保留独特价值,类似扩展帮助数据库开发者重温编程黄金时代,同时推动开源社区多样化创新。 未来类似跨平台兼容项目或将增多,促进老技术在新时代的复苏与应用。
AI 深度解读
背景
《Commodore 64 Basic for PostgreSQL》是一篇来自 Hacker News 的 AI/科技资讯,讲述了将 1982 年 Commodore 64 BASIC 解释器集成到 PostgreSQL 的扩展项目 PL/CBMBASIC。这项技术由 Michael Steil 的 cbmbasic 项目驱动,实现了 1982 年 Microsoft/Commodore 实际解释器的静态再编译,将 6502 ROM 转换为 C 代码并编译成共享库,从而让解释器直接嵌入 PostgreSQL 的后端进程。
核心内容
PL/CBMBASIC 是一个过程化语言扩展,用于在 PostgreSQL 中执行 Commodore 64 BASIC V2 函数体。它不是模仿或致敬,而是直接复刻了 1982 年 Microsoft/Commodore 官方解释器,通过 Michael Steil 的 cbmbasic 项目将 6502 ROM 静态再编译为 C,再编译成扩展的共享库。这意味着解释器直接嵌入 PostgreSQL 的后端进程。
每个函数调用都是内存中的完整“断电重启”:清零 64KB RAM 数组,复位 CPU 寄存器,然后从 $E394 重新进入 ROM。整个仪式仅需 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 行保留),用户代码从行 10 开始。扩展会在函数调用前注入参数作为普通 BASIC 赋值。文本参数 who 映射为 WHO$,小型整型 lives 映射为 LIVES%,其余数字值映射为 40 位 CBM 浮点数(含九个有效数字)。
PostgreSQL 内置了验证器,因为 BASIC V2 有严格的变量命名限制:任何包含 TO、OR、GET 等 BASIC 关键字的变量都会被标记为无效。仅前两个字符有意义,因此 USERNAME 和 USERID 实际对应不同变量,但 ALPHA 和 ALPS 会自动合并为同一变量,TI 和 ST 被系统占用。
对于 OUT/INOUT 参数,扩展会遍历 BASIC 变量表(VARTAB 和 ARYTAB 之间的 7 字节条目),解码类型编码的名称字节,并将 5 字节浮点数、16 位整数和字符串描述符转换回 SQL 值。
设备 8 对应数据库:OPEN 语句的“文件名”是 SQL 查询,通过 SPI 在事务中执行。数据以 CR 结尾的记录流形式返回,ST 状态变量会拾取 EOF 位(64)。次要地址 15 是命令通道,可用于执行 DOS 命令(如 DELETE FROM HISCORES WHERE SCORE < 1000),输出格式为 00,OK,<rows>,0。
运行时错误通过解释器的 ERROR 向量 $0300 捕捉,作为带原始 ROM 错误代码的 PostgreSQL 错误返回。KERNAL 的 STOP 例程被补丁,允许使用 RUN/STOP 键中断查询(响应 statement_timeout)。
关键要点
- 内存重启机制:每个函数调用均执行完整的 64KB RAM 清零 + CPU 复位 + 重新进入 ROM 仪式,耗时仅 15-20 微秒。
- 参数映射规则:文本参数映射为 WHO$,小型整型映射为 LIVES%,其余为 40 位 CBM 浮点数(九个有效数字)。
- 变量命名限制:仅前两个字符有意义,禁止包含 TO/OR/GET 等关键字的变量;PostgreSQL 验证器提前报错。
- OUT/INOUT 参数实现:通过遍历 BASIC 变量表(VARTAB-$2D/$2E 到 ARYTAB-$2F/$30)解码并转换返回。
- 设备 8 数据库映射:OPEN 1,8,0,"SELECT ..." 执行 SQL 查询,INPUT#1 逐记录流式读取,ST 变量拾取 EOF;OPEN 15,8,15 专用于命令通道 DOS 操作。
- 错误与中断处理:错误通过 ERROR 向量 $0300 捕捉并作为 PostgreSQL 错误返回;RUN/STOP 键被补丁以支持 statement_timeout 中断。
- 性能基准:与 PL/Python 相比,复杂查询时性能接近(6 倍左右),因每调用均重启解释器。
- 限制:所有内容大写(无小写),字符串上限 255 字符,无 NULL(用空字符串替代),INPUT 不可用,POKE/SYS 可用于危险操作但需自担风险。
意义与影响
这项扩展不仅为现代数据库提供了 1982 年 Commodore 64 时代的完整复刻体验,更是将怀旧技术带入了生产级数据库生态。它证明了即使是极简的 8 位解释器,在内存重启开销可控的情况下,仍能以接近非内联 SQL 函数的成本实现高性能,并支持传统设备驱动语义(OPEN/INPUT#/CLOSE、ST 状态变量、命令通道)。这为开发者提供了前所未有的“零延迟怀旧”通道,让现代 SQL 程序员在大型表上逐行执行 C64 风格代码成为可能。
在技术层面,它展示了 PostgreSQL 扩展机制的强大灵活性:无需内核修改,仅通过共享库和 SPI 即可桥接完全不同时代的计算模型。超级用户仅限环境进一步强化了其作为教学和实验工具的价值,而非日常生产部署。
从文化角度看,它重燃了对 Commodore 64 的集体记忆,提醒我们技术演进并非线性,而是可以“倒带”到 1982 年并在今天重启运行。最终,它提醒我们:真正的创新往往从对过去的尊重开始,而不仅仅是向未来致敬。
