F.61. pg_variables — функции для работы с переменными различных типов #
Модуль pg_variables
содержит функции для работы с переменными различных типов. Созданные переменные существуют в течение текущего пользовательского сеанса.
F.61.1. Установка #
Расширение pg_variables
включено в состав Postgres Pro. Установив Postgres Pro, вы должны выполнить команду CREATE EXTENSION, чтобы подготовить pg_variables
к работе, следующим образом:
CREATE EXTENSION pg_variables;
F.61.2. Использование #
Модуль pg_variables
содержит функции, позволяющие создавать переменные скалярных типов, переменные-записи и переменные-массивы, читать их и управлять ими. Синтаксис и описания функций представлены в следующих разделах:
В Подразделе F.61.3.1 описываются функции для скалярных переменных.
В Подразделе F.61.3.2 описываются функции для переменных-коллекций записей.
В Подразделе F.61.3.3 описываются функции для переменных-массивов.
В Подразделе F.61.3.4 описываются функции для общих переменных-коллекций.
В Подразделе F.61.3.5 описываются функции для использования итераторов при передвижении по переменным-коллекциям.
В Подразделе F.61.3.6 перечисляются функции, позволяющие управлять всеми переменными в текущем сеансе.
Разобранные примеры использования вы можете найти в Подразделе F.61.5.
Примечание
Если расширение должно использоваться вместе с proxima, перед выполнением команд pg_variables включите принудительный динамический выделенный сеанс с помощью следующей команды:
SET proxima.force_dedicated=true
F.61.2.1. Использование транзакционных переменных #
По умолчанию переменные создаются как нетранзакционные. Успешно созданная переменная продолжает существовать на протяжении всего сеанса, вне зависимости от возможных откатов транзакций. Например:
SELECT pgv_set('vars', 'int1', 101); BEGIN; SELECT pgv_set('vars', 'int2', 102); ROLLBACK; SELECT * FROM pgv_list() order by package, name; package | name | is_transactional ---------+------+------------------ vars | int1 | f vars | int2 | f
Если вы хотите использовать переменную с поддержкой транзакций и точек сохранения, передайте дополнительный флаг is_transactional
в последнем параметре функции, создающей переменную:
BEGIN; SELECT pgv_set('vars', 'trans_int', 101, true); SAVEPOINT sp1; SELECT pgv_set('vars', 'trans_int', 102, true); ROLLBACK TO sp1; COMMIT; SELECT pgv_get('vars', 'trans_int', NULL::int); pgv_get --------- 101
Вы должны указывать флаг is_transactional
при каждом изменении значения транзакционной переменной с помощью функций pgv_set()
и pgv_insert()
. В противном случае произойдёт ошибка. Другим функциям передавать этот флаг не нужно.
SELECT pgv_insert('pack', 'var_record', row(123::int, 'text'::text), true); SELECT pgv_insert('pack', 'var_record', row(456::int, 'another text'::text)); ERROR: variable "var_record" already created as TRANSACTIONAL SELECT pgv_delete('pack', 'var_record', 123::int);
Если вызовы функций pgv_free()
или pgv_remove()
откатываются, затрагиваемые транзакционные переменные восстанавливаются, в отличие от нетранзакционных, которые удаляются необратимо. Например:
SELECT pgv_set('pack', 'var_reg', 123); SELECT pgv_set('pack', 'var_trans', 456, true); BEGIN; SELECT pgv_free(); ROLLBACK; SELECT * FROM pgv_list(); package | name | is_transactional ---------+-----------+------------------ pack | var_trans | t
F.61.3. Функции #
F.61.3.1. Скалярные переменные #
Следующие функции поддерживают скалярные переменные:
Функция | Возвращает |
---|---|
pgv_set(package text, name text, value anynonarray, is_transactional bool default false) | void |
pgv_get(package text, name text, var_type anynonarray, strict bool default true) | anynonarray |
Для функции pgv_get()
вы должны сначала создать пакет и переменную, воспользовавшись функцией pgv_set()
. Если указанный пакет или переменная не существуют, происходит ошибка:
SELECT pgv_get('vars', 'int1', NULL::int); ERROR: unrecognized package "vars"
SELECT pgv_get('vars', 'int1', NULL::int); ERROR: unrecognized variable "int1"
Функция pgv_get()
проверяет тип переменной. Если заданный тип не соответствует типу переменной, выдаётся ошибка:
SELECT pgv_get('vars', 'int1', NULL::text); ERROR: variable "int1" requires "integer" value
F.61.3.2. Коллекции записей #
Следующие функции поддерживают коллекции переменных типа запись.
Функция | Возвращает | Описание |
---|---|---|
pgv_insert(package text, name text, r record, is_transactional bool default false) | void | Вставляет запись в переменную-коллекцию для заданного пакета. Если пакет или переменная не существуют, они создаются автоматически. Первый столбец записи r — первичный ключ. Если запись с таким же первичным ключом уже существует или эта переменная-коллекция имеет другую структуру, выдаётся ошибка. |
pgv_update(package text, name text, r record) | boolean | Изменяет запись с соответствующим первичным ключом (он задаётся в первом столбце r ). Возвращает true , если запись была найдена. Если эта переменная-коллекция имеет другую структуру, выдаётся ошибка. |
pgv_delete(package text, name text, value anynonarray) | boolean | Удаляет запись с соответствующим первичным ключом (он задаётся в первом столбце r ). Возвращает true , если запись была найдена, или false в противном случае. |
pgv_select(package text, name text) | set of records | Возвращает записи из переменной-коллекции. |
pgv_select(package text, name text, value anynonarray) | record | Возвращает записи с соответствующими первичными ключами (первичный ключ задаётся в первом столбце r ). |
pgv_select(package text, name text, value anyarray) | set of records | Возвращает записи из переменных-коллекций с соответствующими первичными ключами (первичный ключ задаётся в первом столбце r ). |
Для использования функций pgv_update()
, pgv_delete()
и pgv_select()
вы должны сначала создать пакет и переменную, воспользовавшись функцией pgv_insert()
. Тип переменной и тип записи должны быть одинаковыми, иначе выдаётся ошибка.
F.61.3.3. Массивы #
Следующие функции поддерживают переменные-массивы:
Функция | Возвращает |
---|---|
pgv_set(package text, name text, value anyarray, is_transactional bool default false) | void |
pgv_get(package text, name text, var_type anyarray, strict bool default true) | anyarray |
Инструкции по использованию этих функций совпадают с приведёнными в Подразделе F.61.3.1 для скалярных переменных.
F.61.3.4. Общие коллекции #
Следующие функции поддерживают общие переменные-коллекции:
Функция | Возвращает | Описание |
---|---|---|
| void | Устанавливает значение для элемента с ключом key переменной-коллекции name в пакете package . Если пакет или переменная не существуют, они создаются автоматически. Внутри одной коллекции разрешены только ключи одного типа. Аргумент key может быть типа int или text . Если элемент с указанным ключом уже существует, его значение изменяется на новое. Параметр is_transactional показывает, является ли новая переменная транзакционной, и по умолчанию имеет значение false . Таким образом, если переменная уже существует, она должна быть транзакционной/нетранзакционной, в зависимости от значения is_transactional , в противном случае возникает ошибка. Если коллекция уже существует и тип его значения не соответствует типу нового значения, также возникает ошибка. |
| anyelement | Возвращает значение элемента с ключом key переменной-коллекции name в пакете package . Если в этой коллекции нет элемента с указанным ключом, возвращается NULL. Аргумент key может быть типа int или text . Если пакет или переменная не существует или указанная переменная не является коллекцией, возникает ошибка. Аргумент val_type необходим для правильного определения типа возвращаемого значения. |
| bool | Возвращает true , если элемент с ключом key существует в переменной-коллекции name в пакете package , и >false в противном случае. Если коллекция или переменная не существует, также возвращается false . Аргумент key может быть типа int или text . Если указанная переменная не является коллекцией, возникает ошибка. |
| void | Удаляет элемент с ключом key переменной-коллекции name из пакета package . Если в этой коллекции нет элемента с указанным ключом, ничего не происходит. Аргумент key может быть типа int или text . Если пакет или переменная не существует или указанная переменная не является коллекции, возникает ошибка. |
Важно
Коллекции, созданные функциями pgv_set_elem()
и pgv_insert()
, считаются несовместимыми.
F.61.3.5. Итераторы #
Следующие функции предназначены для использования итераторов, чтобы передвигаться по переменным-коллекциям. Эти функции работают с коллекциями, созданными функциями pgv_set_elem()
и pgv_insert()
.
Функция | Возвращает | Описание |
---|---|---|
pgv_first(package text, name text, key_type anyelement) | anyelement | Возвращает первый ключ из переменной-коллекции. Коллекции сортируются по ключу в порядке возрастания. Параметр key_type необходим для определения возвращаемого значения. Если переданное значение name не является именем переменной-коллекции, возникает ошибка. |
pgv_last(package text, name text, key_type anyelement) | anyelement | Возвращает последний ключ из переменной-коллекции. Коллекции сортируются по ключу в порядке возрастания. Параметр key_type необходим для определения возвращаемого значения. Если переданное значение name не является именем переменной-коллекции, возникает ошибка. |
pgv_next(package text, name text, key anyelement) | anyelement | Возвращает следующий ключ из переменной-коллекции. Переданный ключ key может отсутствовать в коллекции. Возвращает NULL, если используется для последнего ключа в коллекции. Коллекции сортируются по ключу в порядке возрастания. Если переданное значение name не является именем переменной-коллекции, возникает ошибка. |
pgv_prior(package text, name text, key anyelement) | anyelement | Возвращает предыдущий ключ из переменной-коллекции. Переданный ключ key может отсутствовать в коллекции. Возвращает NULL, если используется для первого ключа в коллекции. Коллекции сортируются по ключу в порядке возрастания. Если переданное значение name не является именем переменной-коллекции, возникает ошибка. |
pgv_count(package text, name text) | integer | Возвращает количество элементов в коллекции. Если переданное значение name не является именем переменной-коллекции, возникает ошибка. |
F.61.3.6. Функции разного назначения #
Функция | Возвращает | Описание |
---|---|---|
pgv_exists(package text, name text) | bool | Возвращает true , если существуют пакет и переменная, или false в противном случае. |
pgv_exists(package text) | bool | Возвращает true , если существуют пакет и переменная, или false в противном случае. |
pgv_remove(package text, name text) | void | Удаляет переменную с заданным именем. Указанный пакет и переменная должны существовать, иначе выдаётся ошибка. |
pgv_remove(package text) | void | Удаляет заданный пакет и все его переменные. Указанный пакет должен существовать, иначе выдаётся ошибка. |
pgv_free() | void | Удаляет все пакеты и переменные. |
pgv_list() | table(package text, name text, is_transactional bool) | Выводит список всех существующих переменных с именем соответствующего пакета и признаком того, что переменная транзакционная. |
pgv_stats() | table(package text, allocated_memory bigint) | Возвращает список созданных пакетов и объём памяти, используемый переменными, в байтах. Если вы используете транзакционные переменные, в этот список также включаются все удалённые пакеты, которые могут быть восстановлены командой ROLLBACK . Эта функция поддерживается только в Postgres Pro версии 9.6 и новее. |
F.61.3.7. Устаревшие функции #
F.61.3.7.1. Целочисленные переменные #
Следующие функции считаются устаревшими. Используйте вместо них универсальные функции для скалярных переменных.
Функция | Возвращает |
---|---|
pgv_set_int(package text, name text, value int, is_transactional bool default false) | void |
pgv_get_int(package text, name text, strict bool default true) | int |
F.61.3.7.2. Текстовые переменные #
Следующие функции считаются устаревшими. Используйте вместо них универсальные функции для скалярных переменных.
Функция | Возвращает |
---|---|
pgv_set_text(package text, name text, value text, is_transactional bool default false) | void |
pgv_get_text(package text, name text, strict bool default true) | text |
F.61.3.7.3. Числовые переменные #
Следующие функции считаются устаревшими. Используйте вместо них универсальные функции для скалярных переменных.
Функция | Возвращает |
---|---|
pgv_set_numeric(package text, name text, value numeric, is_transactional bool default false) | void |
pgv_get_numeric(package text, name text, strict bool default true) | numeric |
F.61.3.7.4. Переменные даты/времени #
Следующие функции считаются устаревшими. Используйте вместо них универсальные функции для скалярных переменных.
Функция | Возвращает |
---|---|
pgv_set_timestamp(package text, name text, value timestamp, is_transactional bool default false) | void |
pgv_get_timestamp(package text, name text, strict bool default true) | timestamp |
F.61.3.7.5. Переменные даты/времени с часовым поясом #
Следующие функции считаются устаревшими. Используйте вместо них универсальные функции для скалярных переменных.
Функция | Возвращает |
---|---|
pgv_set_timestamptz(package text, name text, value timestamptz, is_transactional bool default false) | void |
pgv_get_timestamptz(package text, name text, strict bool default true) | timestamptz |
F.61.3.7.6. Переменные даты #
Следующие функции считаются устаревшими. Используйте вместо них универсальные функции для скалярных переменных.
Функция | Возвращает |
---|---|
pgv_set_date(package text, name text, value date, is_transactional bool default false) | void |
pgv_get_date(package text, name text, strict bool default true) | date |
F.61.3.7.7. Переменные Jsonb #
Следующие функции считаются устаревшими. Используйте вместо них универсальные функции для скалярных переменных.
Функция | Возвращает |
---|---|
pgv_set_jsonb(package text, name text, value jsonb, is_transactional bool default false) | void |
pgv_get_jsonb(package text, name text, strict bool default true) | jsonb |
F.61.4. Важные замечания #
F.61.4.1. Правила сортировки в коллекциях #
Коллекции хранятся в порядке возрастания. Для ключей типа text
потребуется правило сортировки для определения порядка элементов. Если при вставке первого элемента коллекции правило сортировки не указано, используется правило сортировки по умолчанию. В противном случае используется указанное правило сортировки.
F.61.4.2. Курсоры для функций, возвращающих множества #
Все функции, возвращающие множества, за исключением pgv_select(package,variable)
, фиксируют свои результаты при выполнении первой команды FETCH
из курсора, и на них не влияют дальнейшие действия с данными.
Результаты pgv_select(package,variable)
принимаются динамически, и на них влияют транзакции/изменения в коллекции. Для функции pgv_select()
, вызываемой для транзакционной коллекции, снимок коллекции просматривается курсорами при выполнении первой команды FETCH
, но с учётом изменений, которые были сделаны в этой транзакции и в зафиксированных подтранзакциях.
F.61.5. Примеры #
Определение скалярных переменных с помощью функции pgv_set()
и получение их значений с помощью pgv_get()
:
SELECT pgv_set('vars', 'int1', 101); SELECT pgv_set('vars', 'int2', 102); SELECT pgv_set('vars', 'text1', 'text variable'::text); SELECT pgv_get('vars', 'int1', NULL::int); pgv_get ------------- 101 SELECT pgv_get('vars', 'int2', NULL::int); pgv_get ------------- 102 SELECT pgv_get('vars', 'text1', NULL::text); pgv_get --------------- text variable
В предположении, что создана следующая таблица tab
, рассмотрите несколько примеров с переменными-записями:
CREATE TABLE tab (id int, t varchar); INSERT INTO tab VALUES (0, 'str00'), (1, 'str11');
Для работы с переменными-записями можно использовать следующие функции:
SELECT pgv_insert('vars', 'r1', tab) FROM tab; SELECT pgv_select('vars', 'r1'); pgv_select ------------ (1,str11) (0,str00) SELECT pgv_select('vars', 'r1', 1); pgv_select ------------ (1,str11) SELECT pgv_select('vars', 'r1', 0); pgv_select ------------ (0,str00) SELECT pgv_select('vars', 'r1', ARRAY[1, 0]); pgv_select ------------ (1,str11) (0,str00) SELECT pgv_delete('vars', 'r1', 1); SELECT pgv_select('vars', 'r1'); pgv_select ------------ (0,str00)
Проанализируйте поведение транзакционной переменной var_text
при изменении до и после точки сохранения:
SELECT pgv_set('pack', 'var_text', 'before transaction block'::text, true); BEGIN; SELECT pgv_set('pack', 'var_text', 'before savepoint'::text, true); SAVEPOINT sp1; SELECT pgv_set('pack', 'var_text', 'savepoint sp1'::text, true); SAVEPOINT sp2; SELECT pgv_set('pack', 'var_text', 'savepoint sp2'::text, true); RELEASE sp2; SELECT pgv_get('pack', 'var_text', NULL::text); pgv_get --------------- savepoint sp2 ROLLBACK TO sp1; SELECT pgv_get('pack', 'var_text', NULL::text); pgv_get ------------------ before savepoint ROLLBACK; SELECT pgv_get('pack', 'var_text', NULL::text); pgv_get -------------------------- before transaction block
Если вы создадите транзакционную переменную после команд BEGIN
или SAVEPOINT
и затем произойдёт откат к предыдущему состоянию, эта переменная будет удалена:
BEGIN; SAVEPOINT sp1; SAVEPOINT sp2; SELECT pgv_set('pack', 'var_int', 122, true); RELEASE SAVEPOINT sp2; SELECT pgv_get('pack', 'var_int', NULL::int); pgv_get --------- 122 ROLLBACK TO sp1; SELECT pgv_get('pack','var_int', NULL::int); ERROR: unrecognized variable "var_int" COMMIT;
Просмотреть имеющиеся пакеты и переменные:
SELECT * FROM pgv_list() ORDER BY package, name; package | name | is_transactional ---------+----------+------------------ pack | var_text | t vars | int1 | f vars | int2 | f vars | r1 | f vars | text1 | f
Получение объёма памяти, занятой переменными, в байтах:
SELECT * FROM pgv_stats() ORDER BY package; package | allocated_memory ---------+------------------ pack | 16384 vars | 32768
Удаление избранных переменных или пакетов:
SELECT pgv_remove('vars', 'int1'); SELECT pgv_remove('vars');
Удаление всех пакетов и переменных:
SELECT pgv_free();
В этих примерах показано использование переменных-коллекций и функций итераторов:
sql SELECT pgv_set_elem('pack', 'var', 1, 1); SELECT pgv_set_elem('pack', 'var', 5, 5); SELECT pgv_set_elem('pack', 'var', 10, 10); SELECT pgv_first('pack', 'var', NULL::int); pgv_first ----------- 1 SELECT pgv_last('pack', 'var', NULL::int); pgv_last ---------- 10 SELECT pgv_next('pack', 'var', pgv_first('pack', 'var', NULL::int)); pgv_next ---------- 5 SELECT pgv_prior('pack', 'var', pgv_last('pack', 'var', NULL::int)); pgv_prior ----------- 5 SELECT pgv_prior('pack', 'var', pgv_first('pack', 'var', NULL::int)); pgv_prior ----------- SELECT pgv_next('pack', 'var', pgv_last('pack', 'var', NULL::int)); pgv_prior ----------- SELECT pgv_next('pack', 'var', 3); pgv_next ---------- 5 SELECT pgv_prior('pack', 'var', 3); pgv_prior ----------- 1 SELECT pgv_get_elem('pack', 'var', pgv_last('pack', 'var', NULL::int), NULL::int); pgv_get_elem -------------- 10 SELECT pgv_remove_elem('pack', 'var', pgv_last('pack', 'var', NULL::int)); pgv_remove_elem ----------------- SELECT pgv_get_elem('pack', 'var', pgv_last('pack', 'var', NULL::int), NULL::int); pgv_get_elem -------------- 5 (1 row)
Эти примеры показывают, как правила сортировки влияют на порядок элементов в коллекции, а также как перебирать всю коллекцию с помощью циклов PL/pgSQL:
sql SELECT pgv_set_elem('pack', 'var1', 'а' COLLATE "ru_RU", 'а'::text); SELECT pgv_set_elem('pack', 'var1', 'д' COLLATE "ru_RU", 'д'::text); SELECT pgv_set_elem('pack', 'var1', 'е' COLLATE "ru_RU", 'е'::text); SELECT pgv_set_elem('pack', 'var1', 'ё' COLLATE "ru_RU", 'ё'::text); SELECT pgv_set_elem('pack', 'var1', 'ж' COLLATE "ru_RU", 'ж'::text); SELECT pgv_set_elem('pack', 'var1', 'я' COLLATE "ru_RU", 'я'::text); DO $$ DECLARE iter text; BEGIN iter := pgv_first('pack', 'var1', NULL::text); WHILE iter IS NOT NULL LOOP RAISE NOTICE '%', pgv_get_elem('pack', 'var1', iter, NULL::text); iter := pgv_next('pack', 'var1', iter); END LOOP; END; $$; NOTICE: а NOTICE: д NOTICE: е NOTICE: ё NOTICE: ж NOTICE: я SELECT pgv_set_elem('pack', 'var2', 'а' COLLATE "C", 'а'::text); SELECT pgv_set_elem('pack', 'var2', 'д' COLLATE "C", 'д'::text); SELECT pgv_set_elem('pack', 'var2', 'е' COLLATE "C", 'е'::text); SELECT pgv_set_elem('pack', 'var2', 'ё' COLLATE "C", 'ё'::text); SELECT pgv_set_elem('pack', 'var2', 'ж' COLLATE "C", 'ж'::text); SELECT pgv_set_elem('pack', 'var2', 'я' COLLATE "C", 'я'::text); DO $$ DECLARE iter text; BEGIN iter := pgv_first('pack', 'var2', NULL::text); WHILE iter IS NOT NULL LOOP RAISE NOTICE '%', pgv_get_elem('pack', 'var2', iter, NULL::text); iter := pgv_next('pack', 'var2', iter); END LOOP; END; $$; NOTICE: а NOTICE: д NOTICE: е NOTICE: ж NOTICE: я NOTICE: ё
F.61.6. Авторы #
Postgres Professional, Москва, Россия