Session Level Variables qhb-variables
WARNING!
In QHB 1.5.3 release, this feature is experimental and is not recommended for use in a production installation.
Description
qhb-variables allows you to create variables that will be deleted when the
session ends. This mechanism is an alternative to temporary tables in places
where their performance is insufficient. Variables are stored in packages. There
are two types of variables: scalar and table. Scalar variables can store only one
value of any type at a time, while table variables can store multiple rows.
Variables are also divided into transactional and non-transactional. The state
of the former does not depend on the result of the transaction, while the latter
change their value depending on COMMIT and ROLLBACK. The type of a variable
cannot be changed after creation until it is completely deleted (in the case of
a transactional variable, it means before executing COMMIT).
qhb-variables Functions
Functions for Scalar Variables
var_set ( package text, variable text, value
(non)anynonarray, is_transactional bool default false ) → void
Sets the variable value, including updating.
var_get ( package text, variable text, var_type
(non)anynonarray, strict bool default true ) → anynonarray
Gets the variable value.
Usage Examples
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)
Functions for Table Variables
var_insert ( package text, variable text, record record,
is_transactional bool default false ) → void
Inserts a new record into a table variable. The first record column is the primary key. Returns an error if a record with that key already exists or if the record has a different signature.
var_update ( package text, variable text, record record ) →
boolean
Updates a record in a table variable based on a key field. Returns true if the record was updated. If the variable signature differs from the provided string, an error occurs.
var_delete ( package text, variable text, value anynonarray
) → boolean
Deletes a record based on the key. Returns true if the record was deleted.
var_select ( package text, variable text ) → set of record
Returns the current variable value.
var_select ( package text, variable text, value anynonarray
) → record
Returns the current variable value based on the key.
var_select ( package text, variable text, value anyarray
) → set of record
Returns the current variable value based on the keys.
Usage Examples
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)
Common Variable Functions
var_exists ( package text, variable text, is_record bool )
→ bool
Returns true if the variable exists in the given package.
var_exists ( package text ) → bool
Returns true if the package exists.
var_remove ( package text, variable text, is_record bool) →
void
Removes a variable with that name. If the variable or package does not exist, an error will be returned.
var_remove ( package text ) → void
Removes the package with all variables that are contained in it. If the package does not exist, an error will be returned.
var_free () → void
Removes all packages with all their variables.
var_list () → table ( package text, variable text, var_type
text, is_transactional bool )
Returns a list of all packages and variables, indicating their transactionality and type.
var_stats () → table ( alloc_mem bigint )
Returns the amount of memory occupied by variables. Note that this function returns the allocated space, which may not be fully used. For more information, use pg_backend_memory_contexts() function.
There can be two variables with the same name in a package, but only if one of them is a table variable and the other is a scalar variable. By default, the var_exists and var_remove functions remove both variables, so if you need to select only a table variable, pass true as the last parameter, and to remove only a scalar variable, pass false. This parameter is optional.
Example:
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)
Usage Examples
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)
Other Usage Examples
To insert from table and destruct 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)
To change the type while completely deleting a variable:
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); -- successful
var_set
---------
(1 row)
-- SELECT var_set('pack', 'var_transactional', 1::text, true); -- error
COMMIT;
SELECT var_set('pack', 'var_transactional', 1::text, true); -- successful
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)
This example works because the variables were permanently deleted when calling var_free.
To save table elements. Inserting into a variable creates an independent copy of the data.
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
When calling var_select, an instant copy of the data is created, so var_update
will not affect to the result of SELECT. However, if the variable has been
deleted, then it will be impossible to retrieve the remaining data.
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` does not exist in package `pack`
ROLLBACK;
SELECT var_select('pack', 'var');
var_select
------------
(2,third)
(1,second)
(0,first)
(3 rows)