Переменные уровня сессии - qhb-variables
Внимание!
В релизе QHB 1.5.1 эта функциональность является экспериментальной, её использование в установке на производственной среде не рекомендовано.
Описание
Qhb-variables позволяет создавать переменные, которые будут удалены по завершении сессии. Этот
механизм является альтернативой временным таблицам в местах, где их производительности недостаточно.
Переменные хранятся в пакетах. Существует два типа переменных: скалярные и табличные. В скалярных
переменных за раз можно хранить только одно значение любого типа, в табличных же можно
хранить множество строк. Переменные также подразделяются на транзакционные и нетранзакционные.
Состояние первых не зависит от результата транзакции, а вторые меняют своё значение учитывая
COMMIT
и ROLLBACK
. Тип переменной нельзя менять после создания до полного удаления
(в случае транзакционной переменной до COMMIT
'а).
Функции qhb-variables
Функции для работы со скалярными переменными
Функция | Возвращаемое значение | Описание |
---|---|---|
var_set(package text, variable text, value (non)anynonarray, is_transactional bool default false) | void | Установка значения переменной, в том числе обновление |
var_get(package text, variable text, var_type (non)anynonarray, strict bool default true) | anynonarray | Получение значения переменной |
Примеры использования
SELECT var_set('pack', 'var', 0);
var_set
---------
(1 row)
SELECT var_get('pack', 'var', NULL::int);
var_get
---------
0
(1 row)
BEGIN;
SELECT var_set('pack', 'var', 'before savepoint'::text, true);
var_set
---------
(1 row)
SAVEPOINT zero;
SELECT var_set('pack', 'var', 'after savepoint'::text, true);
var_set
---------
(1 row)
SELECT var_get('pack', 'var', NULL::text);
var_get
-----------------
after savepoint
(1 row)
ROLLBACK TO zero;
SELECT var_get('pack', 'var', NULL::text);
var_get
------------------
before savepoint
(1 row)
Функции для работы с табличными переменными
Функция | Возвращаемое значение | Описание |
---|---|---|
var_insert(package text, variable text, r record, is_transactional bool default false) | void | Вставляет новую запись в табличную переменную. Первая колонка записи является первичным ключом. Возвращает ошибку, если запись с таким ключом уже есть или запись имеет другую сигнатуру. |
var_update(package text, variable text, r record) | boolean | Обновляет запись в табличной переменной, опираясь на ключевое поле. Возвращает true , если запись была обновлена. Если сигнатура переменной отличается от предоставленной строки, то возникнет ошибка. |
var_delete(package text, variable text, value anynonarray) | boolean | Удаляет запись по ключу. Возвращает true , если запись была удалена. |
var_select(package text, variable text) | set of record | Возвращает текущее значение переменной. |
var_select(package text, variable text, value anynonarray) | record | Возвращает текущее значение переменной по ключу. |
var_select(package text, variable text, value anyarray) | set of record | Возвращает текущее значение переменной по ключам. |
Примеры использования
SELECT var_insert('pac', 'var', ROW(NULL::int, 0::int));
var_insert
------------
(1 row)
SELECT var_insert('pac', 'var', ROW(0::int, 1::int));
var_insert
------------
(1 row)
SELECT var_insert('pac', 'var1', ROW(0::int, 2::int));
var_insert
------------
(1 row)
SELECT var_insert('pac', 'var1', ROW(2::int, 2::int));
var_insert
------------
(1 row)
SELECT var_select('pac', 'var');
var_select
------------
(,0)
(0,1)
(2 rows)
SELECT var_select('pac', 'var1', 0);
var_select
------------
(0,2)
(1 row)
SELECT var_select('pac', 'var1', ARRAY[0, 1]);
var_select
------------
(0,2)
(1 row)
Общие функции переменных
Функция | Возвращаемое значение | Описание |
---|---|---|
var_exists(package text, variable text, is_record bool) | bool | Возвращает true , если переменная существует в данном пакете. |
var_exists(package text) | bool | Возвращает true , если пакет существует. |
var_remove(package text, variable text, is_record bool) | void | Удаляет переменную по имени. Если переменной или пакета не существует, то будет возвращена ошибка. |
var_remove(package text) | void | Удаляет пакет со всеми переменными внутри него. Если пакета не существует, то будет возвращена ошибка. |
var_free() | void | Удаляет все пакеты со всеми переменными внутри. |
var_list() | table(package text, variable text, variable_type text,is_transactional bool) | Возвращает список всех пакетов и переменных с указанием их транзакционности и типа. |
var_stats() | table(allocated_memory bigint) | Возвращает занимаемое место переменными. Обратите внимание, что эта функция возвращает выделенное место, которое может быть использовано не полностью. За более подробной информацией используйте pg_backend_memory_contexts() |
Примечание
В одном пакете могут быть две переменные с одинаковым названием, но только при условии, что одна из них табличная, а другая скалярная. По умолчанию функцииvar_exists
иvar_remove
удаляют обе переменные, если вам нужно выбрать только табличную переменную, передайте последним параметромtrue
, для удаления только скалярной переменной передайтеfalse
. Этот параметр является опциональным.
BEGIN;
SELECT var_set('pack', 'var', 0, true);
var_set
---------
(1 row)
SELECT var_insert('pack', 'var', ROW(0::int, 1::int), true);
var_insert
------------
(1 row)
SELECT * FROM var_list();
package | variable | variable_type | is_transactional
---------+----------+-------------------------------+------------------
pack | var | Scalar(integer) | t
pack | var | Record(row(integer, integer)) | t
(2 rows)
SAVEPOINT first;
SELECT var_remove('pack', 'var', true);
var_remove
------------
(1 row)
SELECT var_exists('pack', 'var', true);
var_exists
------------
f
(1 row)
SELECT var_exists('pack', 'var', false);
var_exists
------------
t
(1 row)
SELECT var_exists('pack', 'var');
var_exists
------------
t
(1 row)
SELECT var_remove('pack', 'var');
var_remove
------------
(1 row)
SELECT var_exists('pack', 'var', false);
var_exists
------------
f
(1 row)
ROLLBACK TO first;
SELECT var_exists('pack', 'var');
var_exists
------------
t
(1 row)
Примеры использования:
BEGIN;
SELECT var_set('pack', 'var', 'non-transactional'::text);
var_set
---------
(1 row)
SELECT var_set('pack', 'var1', 'transactional'::text, true);
var_set
---------
(1 row)
SELECT * FROM var_list();
package | variable | variable_type | is_transactional
---------+----------+---------------+------------------
pack | var | Scalar(text) | f
pack | var1 | Scalar(text) | t
(2 rows)
SAVEPOINT first;
SELECT var_free();
var_free
----------
(1 row)
SELECT var_stats();
var_stats
-----------
8192
(1 row)
SELECT * FROM var_list();
package | variable | variable_type | is_transactional
---------+----------+---------------+------------------
(0 rows)
ROLLBACK TO first;
SELECT * FROM var_list();
package | variable | variable_type | is_transactional
---------+----------+---------------+------------------
pack | var1 | Scalar(text) | t
(1 row)
Другие примеры использования
Вставка из таблицы и деструктуризация SELECT
CREATE TABLE test_table (id int, t text);
INSERT INTO test_table VALUES (0, 'first'), (1, 'second');
SELECT var_insert('pack', 'var', test_table) FROM test_table;
var_insert
------------
(2 rows)
SELECT var_select('pack', 'var');
var_select
------------
(1,second)
(0,first)
(2 rows)
SELECT * FROM var_select('pack', 'var') AS (id int, t text);
id | t
----+--------
1 | second
0 | first
(2 rows)
Изменение типа при полном удалении переменной
SELECT var_set('pack', 'var', 1::int);
var_set
---------
(1 row)
SELECT var_set('pack', 'var_transactional', 1::int, true);
var_set
---------
(1 row)
SELECT * FROM var_list();
package | variable | variable_type | is_transactional
---------+-------------------+-----------------+------------------
pack | var_transactional | Scalar(integer) | t
pack | var | Scalar(integer) | f
(2 rows)
BEGIN;
SELECT var_free();
var_free
----------
(1 row)
SELECT var_set('pack', 'var', 1::text); -- ok
var_set
---------
(1 row)
-- SELECT var_set('pack', 'var_transactional', 1::text, true); -- Err
COMMIT;
SELECT var_set('pack', 'var_transactional', 1::text, true); -- Ok
var_set
---------
(1 row)
SELECT * FROM var_list();
package | variable | variable_type | is_transactional
---------+-------------------+---------------+------------------
pack | var_transactional | Scalar(text) | t
pack | var | Scalar(text) | f
(2 rows)
Этот пример работает потому что переменные были безвозвратно удалены при вызове var_free
.
Сохранение элементов таблицы
При вставке в переменную создаётся независимая копия данных.
CREATE TABLE test_table (id int, t text);
INSERT INTO test_table VALUES (0, 'first'), (1, 'second'), (2, 'third');
SELECT var_insert('pack', 'var', test_table) FROM test_table WHERE id < 2;
var_insert
------------
(2 rows)
DROP TABLE test_table;
CREATE TABLE test_table AS SELECT * FROM var_select('pack', 'var') AS (id int, t text);
SELECT * FROM test_table;
id | t
----+--------
1 | second
0 | first
(2 rows)
SELECT + CURSOR
При вызове var_select
, создаётся мгновенная копия данных, поэтому на результат SELECT
'а var_update
не повлияет. Однако, если переменная была удалена, тогда получение оставшихся данных станет невозможным.
CREATE TABLE test_table (id int, t text);
INSERT INTO test_table VALUES (0, 'first'), (1, 'second'), (2, 'third');
SELECT var_insert('pack', 'var', test_table, true) FROM test_table;
var_insert
------------
(3 rows)
BEGIN;
DECLARE r1_cur CURSOR FOR SELECT var_select('pack', 'var');
FETCH 1 in r1_cur;
var_select
------------
(2,third)
(1 row)
SELECT var_remove('pack');
var_remove
------------
(1 row)
FETCH 1 in r1_cur;
ERROR: var_select: Existence: Variable with name `var` doesn't exist in package `pack`
ROLLBACK;
SELECT var_select('pack', 'var');
var_select
------------
(2,third)
(1,second)
(0,first)
(3 rows)