Databases
Two drivers ship with the language: PostgreSQL over the wire, and reading an SQLite file. Both are written in flang itself; both are checked by examples with no database present.
Who carries the bytes
A flang program opens no sockets and no files. It returns a plan — a description of an action: "open a connection there", "send these bytes", "read the answer". The description is carried out by whoever ran the plan.
That is why building messages and parsing answers stay ordinary total functions, and why flang check needs no server.
PostgreSQL: connect and query
| file | what is in it | lines | functions | examples |
|---|---|---|---|---|
flang/stdlib/wire.flang | octets, network-order integers, NUL-terminated strings, cutting a stream | 1098 | 34 | 77 |
flang/stdlib/postgres.flang | protocol version 3.0: client messages built, server answers parsed | 1871 | 67 | 126 |
examples/db/postgres-plan.flang | the whole five-step conversation | 554 | 55 |
A simple query is built like this — taken from the tree verbatim:
тотальная функция «Простой запрос»
принимает запрос: строка
возвращает «Печать»
обеспечивает «простой запрос едет буквой Q, а вместе с длиной и завершающим нулём весит на шесть байтов больше самого запроса» разбор результат
случай вариант «Напечатано» с текст как текст
то (текст начинается с "Q") и притом ((«Байтов в тексте» от текст) равен (6 плюс («Байтов в тексте» от запрос)))
случай вариант «Число непечатаемо» с значение как названо
то названо равен (5 плюс («Байтов в тексте» от запрос))
обеспечивает «простой запрос едет кадром Q со строкой с нулём» (не («Четыре октета печатаются» от (4 плюс («Байтов в тексте» от («Строка с нулём» от запрос))))) или (результат равен (вариант «Напечатано» с текст равным (соединить (соединить "Q" с («Четыре октета» от (4 плюс («Байтов в тексте» от («Строка с нулём» от запрос))))) с («Строка с нулём» от запрос))))
обеспечивает «непечатаемая длина простого запроса названа числом» («Четыре октета печатаются» от (4 плюс («Байтов в тексте» от («Строка с нулём» от запрос)))) или (результат равен (вариант «Число непечатаемо» с значение равным (4 плюс («Байтов в тексте» от («Строка с нулём» от запрос)))))
пример «запрос едет буквой Q»
дано запрос равно "a"
ожидается вариант «Напечатано» с текст равным "Q\u0000\u0000\u0000\u0006a\u0000"
«Кадр» от "Q" и («Строка с нулём» от запрос)
Taken from the tree verbatim — flang/stdlib/postgres.flang.
Checking and examples need no database:
$ flang check flang/stdlib/postgres.flang
$ flang test flang/stdlib/postgres.flang
The conversation itself does need a live server:
$ flang io examples/db/postgres-plan.flang | python3 -c \
"import sys,json; print(json.load(sys.stdin)['result'])"
1 пуск: | | | in_hot_standby=off … server_version=17.10 server_encoding=UTF8
2 создание: INSERT 0 1| | |
3 вставка с параметрами: INSERT 0 1| | |
4 выборка: SELECT 2| | 1 Мир ; 2 dva|
5 отказ: | ERROR 42703 column "netakoykolonki" does not exist| |
Five steps: start-up with a cleartext password, create, insert with parameters ($1, $2), select, and a deliberately wrong query answered with the server's own code. Cyrillic travels in both directions. Without the pipe the command prints one JSON object: result is the report above, log is every order and every answer in full.
The plan connects to 127.0.0.1:55434 as user flang, database postgres. Address, port, user and password stand in the plan as literals: a plan takes no arguments, and a program does not see the environment. Change them by editing the functions at the top of the plan.
PostgreSQL: what works and what does not
trust and cleartext password | works |
md5, scram-sha-256 | no: HMAC and PBKDF2 are not in the library. The plan keeps reading and waits |
| TLS | no. The conversation runs in the clear — for a database on the same machine |
column types in RowDescription | only the number of columns is taken out. Pass the type number of a column yourself |
| a null value | not parsed: its length is minus one, and parsing asks for 4 294 967 295 octets |
| length of a message you send | the four octets of the length must all be below 128; a query is padded with spaces, 200 in reserve. A parameter value is at most 127 bytes |
| one parsing pass | at most 1000 messages |
| a corrupt stream | stops the parse with a distinct answer, not silently |
SQLite: read a file
flang/stdlib/sqlite.flang reads an SQLite 3 database as a list of octets: the file image comes in through one order, Прочитать октеты из файла. No server, nothing on the wire.
Make a sample database with someone else's sqlite3 and read it back:
$ python3 -c "import sqlite3,os; d='/srv/tmp/sqlite-obrazec'; os.makedirs(d,exist_ok=True); \
c=sqlite3.connect(d+'/proba.db'); c.execute('create table люди(имя text, лет integer)'); \
c.executemany('insert into люди values (?,?)',[('Аня',31),('Боря',44),('Вера',7)]); c.commit()"
$ flang io examples/db/sqlite-read.flang | python3 -c \
"import sys,json; print(json.load(sys.stdin)['result'])"
магия SQLite: да
размер страницы: 4096
страниц: 2
октетов в файле: 8192
таблицы: люди
корень таблицы люди: 2
SQL: CREATE TABLE люди(имя text, лет integer)
строк: 3
1 | Аня | 31
2 | Боря | 44
3 | Вера | 7
The plan is examples/db/sqlite-read.flang; the path to the file and the name of the table stand in it as two one-line functions — «Откуда» and «Какая таблица».
SQLite: what works and what does not
| the header | magic, page size, number of pages |
the schema page sqlite_master | table names, their root pages, their SQL |
| a table b-tree leaf | cell pointers, payload length, row number, the payload |
| a record | null, integers of all six widths, the 0 and 1 of serial types 8 and 9, text through UTF-8, binary |
| real numbers (serial type 7) | the eight octets are handed over as they are, in variant «Дробное» |
| writing | no. A reading driver is the half that can be checked without breaking someone's file |
| internal b-tree pages and overflow | no. They begin on a table larger than one page; empty is returned rather than a forgery. «Вид страницы» answers 13 for a table leaf and 5 for an internal page |
| indexes (page kinds 2 and 10) | no: they are not table rows |
Where to go next
- Processes, supervision, distribution — who holds the connection while work is going on.
- Embedding flang — how the driver gets into a program in your language.