flang the compiler proves your program cannot hang 0.6.2 GitHub Русский

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.

Who carries the bytes between the program and the databaseflang programplan runnerPostgreSQLdescription of an actionbytesbytesanswer as a value
Who carries the bytes between the program and the database

That is why building messages and parsing answers stay ordinary total functions, and why flang check needs no server.

PostgreSQL: connect and query

filewhat is in itlinesfunctionsexamples
flang/stdlib/wire.flangoctets, network-order integers, NUL-terminated strings, cutting a stream10983477
flang/stdlib/postgres.flangprotocol version 3.0: client messages built, server answers parsed187167126
examples/db/postgres-plan.flangthe whole five-step conversation55455

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 passwordworks
md5, scram-sha-256no: HMAC and PBKDF2 are not in the library. The plan keeps reading and waits
TLSno. The conversation runs in the clear — for a database on the same machine
column types in RowDescriptiononly the number of columns is taken out. Pass the type number of a column yourself
a null valuenot parsed: its length is minus one, and parsing asks for 4 294 967 295 octets
length of a message you sendthe 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 passat most 1000 messages
a corrupt streamstops 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 headermagic, page size, number of pages
the schema page sqlite_mastertable names, their root pages, their SQL
a table b-tree leafcell pointers, payload length, row number, the payload
a recordnull, 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 «Дробное»
writingno. A reading driver is the half that can be checked without breaking someone's file
internal b-tree pages and overflowno. 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