Транзакции¶
В Picodata поддерживаются транзакции — блоки команд. В рамках транзакции пользователь может выполнить несколько SQL-запросов атомарно — так, как если бы это был единый запрос. Для транзакционных запросов действуют ограничения.
Структура¶
Транзакционный блок представляет собой запрос вида DO $$ BEGIN ... END $$;,
внутри которого можно поместить набор вложенных запросов. Такой блок
функционально является неименованной процедурой.
Поддерживаемые команды исполнения¶
На данный момент для транзакционных блоков поддерживаются следующие команды исполнения:
<DML>— выполнить вложенный DML-запрос (см. ограничения ниже).RETURN QUERY <DQL>— выполнить вложенный запрос и отобразить результат выполнения (используется для DQL-запросов).LET <name> = (<DQL>)— выполнить вложенный запрос, возвращающий одну колонку, и сохранить результат в переменной<name>, доступной в последующих командах блока (см. ниже).IF <expr> THEN ... END IF;— условно выполнить вложенные DML-команды, если выражение<expr>истинно (см. ниже).
Пример использования¶
DO $$ BEGIN
LET cur = (SELECT money FROM bank WHERE id = 1);
RETURN QUERY SELECT cur;
IF cur >= 100 THEN
UPDATE bank SET money = money - 100 WHERE id = 1;
UPDATE bank SET money = money + 100 WHERE id = 1;
END IF;
END $$;
LET-переменные¶
Команда LET связывает результат однострочного запроса с одной
колонкой с именованной переменной, которую можно использовать в
последующих командах блока (в том числе в выражениях WHERE,
SET, в условии IF и в RHS другого LET):
DO $$ BEGIN
LET price = (SELECT price FROM store WHERE id = 2);
UPDATE warehouse SET price = price * 2 WHERE id = 2;
END $$;
Ограничения для LET:
- RHS должен возвращать ровно одну колонку. Если выборка возвращает
более одной строки, то будет возвращенна последняя строка из
выборки. Если выборка пуста, переменная получает значение
NULL. - Переменная не может быть объявлена повторно с другим типом. Повторное объявление с тем же типом разрешено и переиспользует существующий слот.
- Объявленная переменная обязана быть использована хотя бы в одной последующей команде блока. Неиспользованная переменная приводит к ошибке планирования.
- Если имя
LET-переменной совпадает с именем колонки таблицы, доступной в запросе, ссылка считается неоднозначной и отклоняется.
Условные блоки IF¶
Команда IF <expr> THEN ... END IF; выполняет вложенные
DML-команды, если выражение <expr> истинно.
DO $$ BEGIN
LET cur = (SELECT money FROM bank WHERE id = 1);
IF cur >= 100 THEN
UPDATE bank SET money = money - 100 WHERE id = 1;
UPDATE bank SET money = money + 100 WHERE id = 1;
END IF;
END $$;
Ограничения для IF:
- Условие должно быть скалярным булевым выражением; ссылки на колонки
таблиц в условии не допускаются — используйте
LETдля подготовки значений. - В теле допускаются только DML-команды (
UPDATE/DELETE/INSERT). КомандыLET,RETURN QUERYи вложенныйIFвнутри тела не разрешены.
Ограничения¶
Поддержка транзакционного выполнения команд в Picodata имеет ограничения:
- В рамках одной транзакции нельзя обращаться к более чем одному движку хранения
- Все запросы к шардированным таблицам внутри блока должны
затрагивать только один бакет. При нарушении этого условия
Picodata вернет пользователю ошибку. В будущем появится поддержка
команды
EXPLAINдля транзакционных блоков, с помощью которой можно будет наглядно увидеть затронутые бакеты. - Поддерживаются только запросы, не требующие перемещения данных. Иными словами, в текущей реализации транзакции должны быть выполнимы в рамках одного узла Picodata. Глобальные транзакции, затрагивающие данные на нескольких узлах, не поддерживаются.
- Для глобальных таблиц поддерживаются только читающие запросы (DQL), но не модифицирующие (DML).
- Читающие команды в блоке должны располагаться строго до
модифицирующих: то есть, все
RETURN QUERY SELECT ...должны идти до DML и дальше уже появиться не могут.