Весь старый Commodore 64 теперь живёт внутри PostgreSQL. PL/CBMBASIC — это процедурное расширение, которое запускает функции прямо на интерпретаторе BASIC V2 из 1982 года. В основе лежит проект Майкла Штайля cbmbasic, который статически перекомпилировал 6502 ROM в C, а тот уже собран в shared library расширения.
Каждый вызов функции — это перезагрузка C64 в памяти. Ноль RAM на 64 КБ, сброс регистров CPU, вход в ROM. Весь цикл занимает 15–20 микросекунд. Это примерно в тысячу раз быстрее, чем настоящий C64 когда-либо мог. Этого хватает, чтобы дёргать функцию на каждой строке большой таблицы почти без задержек.
Код пишется с обязательными номерами строк. Нулевая — девятая зарезервированы. Туда подставляются аргументы функции как обычные присваивания BASIC. text параметр who превращается в WHO$, smallint — в LIVES%, всё остальное — в 40-битный CBM float.
Валидатор строгий. Он воспроизводит все причуды оригинального токенизатора прямо на этапе CREATE FUNCTION. Назвать переменную TOTAL нельзя — оно содержит ключевое слово TO. SCORE — содержит OR. BUDGET — GET. Значимы только первые два символа имени, так что ALPHA и ALPS — одна и та же строка. Ошибка выдаётся с подсказкой из документации.
OUT и INOUT параметры работают через честное чтение таблицы переменных BASIC. Когда программа завершается, значения сидят в эмулированной памяти. Хендлер лезет в VARTAB и ARYTAB, декодирует байты имён и преобразует 5-байтовые float обратно в SQL. Кража памяти из другого процесса для получения результатов — такого в документации PostgreSQL вы не увидите.
База данных — это устройство 8. Как на C64. SQL-запросы выполняются через SPI. OPEN 1,8,0,"SELECT NAME, SCORE..." — работаем внутри транзакции. Строки приходят по одной, а ST ловит бит EOF (64) на последнем байте — прямо как дисковод 1541. Вторичный адрес 15 — командный канал дисковода. PRINT#15,"DELETE FROM HISCORES..." — работает. Статус возвращает 0,OK,<rows>,0. Каждый PRINT# склеивается, так что можно отправлять запросы длиннее 255 символов. INSERT, UPDATE, DDL — всё что угодно. Это untrusted язык только для суперпользователей.
Ошибки ловятся через вектор ERROR из ROM по адресу $0300. Вместо зависания приходит нормальный PostgreSQL error: ?DIVISION BY ZERO ERROR IN 20. А KERNAL патчится на CHECK_FOR_INTERRUPTS(), так что вечный 10 GOTO 10 чисто обрубается по statement_timeout.
По скорости: PL/Python быстрее в 14–19 раз на тривиальных вызовах и примерно в 6 раз на работе с сотней строк, где у них общие накладные расходы на SPI. Но эти 15 микросекунд ставят C64 в одну ценовую категорию с неинлайновой SQL-функцией. Интерпретатор перемалывает около миллиона операторов BASIC в секунду — против тысячи на реальном C64.
Всё в верхнем регистре, строки до 255 символов, числа с девятью значащими цифрами. NULL нет — он приходит как пустая строка. INPUT сломается, клавиатуры к базе не подключено. Любители риска могут делать POKE и SYS в эмулированную память, но эффект исчезнет на следующем вызове. Код лежит на github.com/darkixion/pl-cbmbasic.
READY. █