From 7c5081ee57d216694b90572e7aa0804238c9c49d Mon Sep 17 00:00:00 2001 From: Victor Wagner Date: Thu, 2 Apr 2020 16:52:03 +0300 Subject: [PATCH 01/46] Remove executable build from C sources because rpmbuild complains about it --- pg_variables.c | 0 pg_variables.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 pg_variables.c mode change 100755 => 100644 pg_variables.h diff --git a/pg_variables.c b/pg_variables.c old mode 100755 new mode 100644 diff --git a/pg_variables.h b/pg_variables.h old mode 100755 new mode 100644 From 13a77d594b258a0baf0623a8eb1c7f791bbe91ee Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Thu, 8 Oct 2020 15:57:23 +0300 Subject: [PATCH 02/46] Add support for PostgreSQL 13. --- pg_variables.c | 7 +++++-- pg_variables_record.c | 13 ++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/pg_variables.c b/pg_variables.c index 781b460..0c6dca2 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -2106,8 +2106,11 @@ static void compatibility_check(void) { #ifdef PGPRO_EE - if (getNestLevelATX() != 0) - elog(ERROR, "pg_variable extension is not compatible with autonomous transactions and connection pooling"); +# if (PG_VERSION_NUM < 130000) || \ + ((PG_VERSION_NUM >= 130000) && (defined PGPRO_FEATURE_ATX)) + if (getNestLevelATX() != 0) + elog(ERROR, "pg_variable extension is not compatible with autonomous transactions and connection pooling"); +# endif #endif } diff --git a/pg_variables_record.c b/pg_variables_record.c index beba0d6..b97ffca 100644 --- a/pg_variables_record.c +++ b/pg_variables_record.c @@ -11,7 +11,18 @@ #include "funcapi.h" #include "access/htup_details.h" -#include "access/tuptoaster.h" +/* + * See https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=8b94dab06617ef80a0901ab103ebd8754427ef + * + * Split tuptoaster.c into three separate files. + */ +#if PG_VERSION_NUM >= 130000 +# include "access/detoast.h" +# include "access/heaptoast.h" +#else +# include "access/tuptoaster.h" +#endif + #include "catalog/pg_collation.h" #include "catalog/pg_type.h" #include "utils/builtins.h" From e1a502a32ad5cab838813011898387931b10c622 Mon Sep 17 00:00:00 2001 From: ziva777 Date: Wed, 14 Oct 2020 20:01:38 +0300 Subject: [PATCH 03/46] Issue #27: Error with transactional pgv_insert/pgv_remove (#28) Authored-by: Maxim Orlov --- expected/pg_variables_trans.out | 335 ++++++++++++++++++++++++++++++++ pg_variables.c | 51 +++-- pg_variables.h | 1 + sql/pg_variables_trans.sql | 80 ++++++++ 4 files changed, 456 insertions(+), 11 deletions(-) diff --git a/expected/pg_variables_trans.out b/expected/pg_variables_trans.out index 025cc77..d73ef69 100644 --- a/expected/pg_variables_trans.out +++ b/expected/pg_variables_trans.out @@ -2032,3 +2032,338 @@ SELECT pgv_free(); (1 row) +-- Variables should be insertable after pgv_remove (variable) +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | x | t +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +-- Variables should be insertable after pgv_remove (package) +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | x | t +(1 row) + +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | y | t +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +-- Variables should be insertable after pgv_free +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | y | t +(1 row) + +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | z | t +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/pg_variables.c b/pg_variables.c index 0c6dca2..ee1fa3d 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -56,7 +56,7 @@ static Variable *getVariableInternal(Package *package, text *name, static Variable *createVariableInternal(Package *package, text *name, Oid typid, bool is_record, bool is_transactional); static void removePackageInternal(Package *package); -static void resetVariablesCache(bool with_package); +static void resetVariablesCache(void); /* Functions to work with transactional objects */ static void createSavepoint(TransObject *object, TransObjectType type); @@ -403,7 +403,15 @@ variable_insert(PG_FUNCTION_ARGS) * record type or if last record has different id. */ tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); - check_attributes(variable, tupdesc); + if (variable->is_deleted) + { + init_record(record, tupdesc, variable); + variable->is_deleted = false; + } + else + { + check_attributes(variable, tupdesc); + } } LastTypeId = tupType; @@ -901,6 +909,7 @@ remove_variable(PG_FUNCTION_ARGS) createSavepoint(transObject, TRANS_VARIABLE); addToChangesStack(transObject, TRANS_VARIABLE); } + variable->is_deleted = true; GetActualState(variable)->is_valid = false; GetPackState(package)->trans_var_num--; if ((GetPackState(package)->trans_var_num + numOfRegVars(package)) == 0) @@ -909,7 +918,7 @@ remove_variable(PG_FUNCTION_ARGS) else removeObject(&variable->transObject, TRANS_VARIABLE); - resetVariablesCache(false); + resetVariablesCache(); PG_FREE_IF_COPY(package_name, 0); PG_FREE_IF_COPY(var_name, 1); @@ -936,7 +945,7 @@ remove_package(PG_FUNCTION_ARGS) package = getPackage(package_name, true); removePackageInternal(package); - resetVariablesCache(true); + resetVariablesCache(); PG_FREE_IF_COPY(package_name, 0); PG_RETURN_VOID(); @@ -945,7 +954,27 @@ remove_package(PG_FUNCTION_ARGS) static void removePackageInternal(Package *package) { - TransObject *transObject; + TransObject *transObject; + Variable *variable; + HTAB *htab; + HASH_SEQ_STATUS vstat; + int i; + + /* Mark all the valid variables from package as deleted */ + for (i = 0; i < 2; i++) + { + if ((htab = pack_htab(package, i)) != NULL) + { + hash_seq_init(&vstat, htab); + + while ((variable = + (Variable *) hash_seq_search(&vstat)) != NULL) + { + if (GetActualState(variable)->is_valid) + variable->is_deleted = true; + } + } + } /* All regular variables will be freed */ if (package->hctxRegular) @@ -983,11 +1012,10 @@ isPackageEmpty(Package *package) * of some changes: removing, rollbacking, etc. */ static void -resetVariablesCache(bool with_package) +resetVariablesCache(void) { /* Remove package and variable from cache */ - if (with_package) - LastPackage = NULL; + LastPackage = NULL; LastVariable = NULL; LastTypeId = InvalidOid; } @@ -1013,7 +1041,7 @@ remove_packages(PG_FUNCTION_ARGS) removePackageInternal(package); } - resetVariablesCache(true); + resetVariablesCache(); PG_RETURN_VOID(); } @@ -1596,6 +1624,7 @@ createVariableInternal(Package *package, text *name, Oid typid, bool is_record, variable->package = package; variable->is_record = is_record; variable->is_transactional = is_transactional; + variable->is_deleted = false; initObjectHistory(transObject, TRANS_VARIABLE); if (!isObjectChangedInCurrentTrans(&package->transObject)) @@ -1728,7 +1757,7 @@ removeObject(TransObject *object, TransObjectType type) GetActualState(&package->transObject)->is_valid = false; } - resetVariablesCache(true); + resetVariablesCache(); } /* @@ -2096,7 +2125,7 @@ processChanges(Action action) MemoryContextDelete(ModuleContext); packagesHash = NULL; ModuleContext = NULL; - resetVariablesCache(true); + resetVariablesCache(); changesStack = NULL; changesStackContext = NULL; } diff --git a/pg_variables.h b/pg_variables.h index 3e233bd..b08faa6 100644 --- a/pg_variables.h +++ b/pg_variables.h @@ -113,6 +113,7 @@ typedef struct Variable * specified only when creating a variable. */ bool is_transactional; + bool is_deleted; } Variable; typedef struct HashRecordKey diff --git a/sql/pg_variables_trans.sql b/sql/pg_variables_trans.sql index c4effd9..c4b8c90 100644 --- a/sql/pg_variables_trans.sql +++ b/sql/pg_variables_trans.sql @@ -534,3 +534,83 @@ ROLLBACK; SELECT package FROM pgv_stats() ORDER BY package; SELECT pgv_free(); + +-- Variables should be insertable after pgv_remove (variable) +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); +SELECT pgv_select('test', 'x'); +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); +SELECT pgv_select('test', 'x'); +ROLLBACK; + +SELECT * FROM pgv_list() order by package, name; + +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); +SELECT pgv_select('test', 'x'); +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); +SELECT pgv_select('test', 'x'); +COMMIT; + +SELECT * FROM pgv_list() order by package, name; +SELECT pgv_select('test', 'x'); + +-- Variables should be insertable after pgv_remove (package) +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); +SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); +SELECT pgv_select('test', 'y'); +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); +SELECT pgv_select('test', 'y'); +ROLLBACK; + +SELECT * FROM pgv_list() order by package, name; + +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); +SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); +SELECT pgv_select('test', 'y'); +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); +SELECT pgv_select('test', 'y'); +COMMIT; + +SELECT * FROM pgv_list() order by package, name; +SELECT pgv_select('test', 'y'); + +-- Variables should be insertable after pgv_free +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); +SELECT pgv_select('test', 'z'); +SELECT pgv_free(); +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); +SELECT pgv_select('test', 'z'); +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); +SELECT pgv_select('test', 'z'); +ROLLBACK; + +SELECT * FROM pgv_list() order by package, name; + +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); +SELECT pgv_select('test', 'z'); +SELECT pgv_free(); +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); +SELECT pgv_select('test', 'z'); +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); +SELECT pgv_select('test', 'z'); +COMMIT; + +SELECT * FROM pgv_list() order by package, name; +SELECT pgv_select('test', 'z'); + +SELECT pgv_free(); From 30e072295e8dfdf588eabfe7e38bcd7366d2cfd8 Mon Sep 17 00:00:00 2001 From: Alexey Kondratov Date: Thu, 15 Oct 2020 14:30:11 +0300 Subject: [PATCH 04/46] Run CI tests fro Postgres 12 and 13 --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7edda6c..495cf4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,12 @@ notifications: on_failure: always env: + - PG_VERSION=13 LEVEL=nightmare + - PG_VERSION=13 LEVEL=hardcore + - PG_VERSION=13 + - PG_VERSION=12 LEVEL=nightmare + - PG_VERSION=12 LEVEL=hardcore + - PG_VERSION=12 - PG_VERSION=11 LEVEL=nightmare - PG_VERSION=11 LEVEL=hardcore - PG_VERSION=11 @@ -27,4 +33,4 @@ env: matrix: allow_failures: - - env: PG_VERSION=11 LEVEL=nightmare + - env: LEVEL=nightmare From 49807a2e1fe454c84aa5303d0b79090eebd5cb86 Mon Sep 17 00:00:00 2001 From: Alexey Kondratov Date: Thu, 15 Oct 2020 15:21:19 +0300 Subject: [PATCH 05/46] Fix .travis.yml --- .travis.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 495cf4b..5882736 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,3 @@ -sudo: required - language: c services: @@ -21,16 +19,19 @@ env: - PG_VERSION=13 LEVEL=nightmare - PG_VERSION=13 LEVEL=hardcore - PG_VERSION=13 - - PG_VERSION=12 LEVEL=nightmare + # - PG_VERSION=12 LEVEL=nightmare - PG_VERSION=12 LEVEL=hardcore - PG_VERSION=12 - - PG_VERSION=11 LEVEL=nightmare + # - PG_VERSION=11 LEVEL=nightmare - PG_VERSION=11 LEVEL=hardcore - PG_VERSION=11 - PG_VERSION=10 - PG_VERSION=9.6 - PG_VERSION=9.5 +# XXX: consider fixing nightmare mode matrix: allow_failures: - - env: LEVEL=nightmare + - env: PG_VERSION=11 LEVEL=nightmare + - env: PG_VERSION=12 LEVEL=nightmare + - env: PG_VERSION=13 LEVEL=nightmare From a1356048b680b88cd9ba11f83e5e680a531421e6 Mon Sep 17 00:00:00 2001 From: Alexey Kondratov Date: Thu, 15 Oct 2020 15:54:32 +0300 Subject: [PATCH 06/46] Try to fix nightmare mode --- Dockerfile.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.tmpl b/Dockerfile.tmpl index 1760377..0bcd176 100644 --- a/Dockerfile.tmpl +++ b/Dockerfile.tmpl @@ -5,7 +5,7 @@ RUN apk add --no-cache \ openssl curl \ perl perl-ipc-run \ make musl-dev gcc bison flex coreutils \ - zlib-dev libedit-dev \ + zlib-dev libedit-dev linux-headers \ clang clang-analyzer; # Install fresh valgrind From 080cb1c68708591f73e0d95d447a2f7ae201620b Mon Sep 17 00:00:00 2001 From: ziva777 Date: Fri, 30 Oct 2020 13:27:33 +0300 Subject: [PATCH 07/46] Bugfix/issue 27 (#29) * Issue #27: Error with transactional pgv_insert/pgv_remove * Issue #27: Error with transactional pgv_insert/pgv_remove - review * Issue #27: Add fix and improve tests. * Issue #27: Fix for backend termination on transaction commit. * Issue #27: Add fix for leaked hash_seq_search. Fix warning: leaked hash_seq_search scan for hash table. * Issue #27: Add tests and comment. * Issue #27: Add fix for leaked hash_seq_search for pgv_stats. * Issue #27: Add fix for VALGRING failed test. * Issue #27: Add fix for Travis Ci failed tests. * Issue #27: Fix tests for pgv_stats on 9.5 * Fix some comments Co-authored-by: Maxim Orlov Co-authored-by: Alexey Kondratov --- expected/pg_variables_trans.out | 1286 ++++++++++ expected/pg_variables_trans_1.out | 3655 +++++++++++++++++++++++++++++ pg_variables.c | 262 ++- sql/pg_variables_trans.sql | 461 ++++ 4 files changed, 5639 insertions(+), 25 deletions(-) create mode 100644 expected/pg_variables_trans_1.out diff --git a/expected/pg_variables_trans.out b/expected/pg_variables_trans.out index d73ef69..2ce8138 100644 --- a/expected/pg_variables_trans.out +++ b/expected/pg_variables_trans.out @@ -2367,3 +2367,1289 @@ SELECT pgv_free(); (1 row) +-- Variables should be rollbackable if transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +--- +--- Variables should not be rollbackable if not transactional +--- +-- case 1 (remove var) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 2 (remove pack) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 3 (free) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- clear all +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #1 (remove var) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "y" +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #2 (remove pack) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #3 (free) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #4 +--- +-- non transactional, remove var +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, remove pac +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, free +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional, remove var +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, remove pack +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, free +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #5 +--- +-- non transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +--- +--- Cursor test #6 +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +COMMIT; +--- +--- Tests for "leaked hash_seq_search scan for hash table" +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +--- +--- Some special cases +--- +-- take #1 +SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +SELECT pgv_remove('test', 'z1'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "z1" +ROLLBACK; +SELECT pgv_select('test', 'z1'); + pgv_select +------------ + (2,2) +(1 row) + +-- take #2 +SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +SELECT pgv_remove('test', 'z2'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "z2" +ROLLBACK; +SELECT pgv_select('test', 'z2'); +ERROR: unrecognized variable "z2" +SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +-- take #3 +SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'z3'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "z3" +ROLLBACK; +SELECT pgv_select('test', 'z3'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'z3'); + pgv_remove +------------ + +(1 row) + +COMMIT; +SELECT pgv_select('test', 'z3'); +ERROR: unrecognized variable "z3" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- take #4 +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +SAVEPOINT sp1; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +--- +--- Test cases for pgv_stats +--- +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); +ERROR: there is a record in the variable "y" with same key +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); +ERROR: variable "x" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/expected/pg_variables_trans_1.out b/expected/pg_variables_trans_1.out new file mode 100644 index 0000000..bc55b84 --- /dev/null +++ b/expected/pg_variables_trans_1.out @@ -0,0 +1,3655 @@ +SET timezone = 'Europe/Moscow'; -- Need to proper output of datetime variables +--CHECK SAVEPOINT RELEASE +BEGIN; +-- Declare variables +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'some value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 101, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 102); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', NULL, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's101', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's102'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.01, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.02); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-03-30'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); + pgv_set_jsonb +--------------- + +(1 row) + +SAVEPOINT comm; +-- Set new values +SELECT pgv_set('vars', 'any1', 'another value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'another value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 103, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 103); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', 104, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's103', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's103'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.03, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.03); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 12:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 12:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 12:00:00 GMT+03', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 12:00:00 GMT+03'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-04-02', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-04-02'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'); + pgv_set_jsonb +--------------- + +(1 row) + +-- Check values before releasing savepoint +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +-- Check values after releasing savepoint +RELEASE comm; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +COMMIT; +CREATE TABLE tab (id int, t varchar); +INSERT INTO tab VALUES (0, 'str00'), (1, 'str33'), (2, NULL), (NULL, 'strNULL'); +BEGIN; +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SELECT pgv_insert('vars3', 'r2', tab) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SAVEPOINT comm; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +RELEASE comm; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +COMMIT; +--CHECK SAVEPOINT ROLLBACK +BEGIN; +-- Variables are already declared +SAVEPOINT comm2; +-- Set new values +SELECT pgv_set('vars', 'any1', 'one more value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'one more value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 101, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 102); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', NULL, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's101', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's102'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.01, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.02); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-03-30'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); + pgv_set_jsonb +--------------- + +(1 row) + +-- Check values before rollback to savepoint +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 101 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 102 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s101 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s102 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.01 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.02 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 10:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 11:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 14:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 16:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 03-29-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 03-30-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +--------------------- + [1, 2, "foo", null] +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +-------------------------------------------------- + {"bar": "baz", "active": false, "balance": 7.77} +(1 row) + +-- Check values after rollback to savepoint +ROLLBACK TO comm2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 102 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s102 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.02 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 11:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 16:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 03-30-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +-------------------------------------------------- + {"bar": "baz", "active": false, "balance": 7.77} +(1 row) + +COMMIT; +-- Record variables +BEGIN; +SAVEPOINT comm2; +SELECT pgv_delete('vars3', 'r1', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_delete('vars3', 'r2', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +ROLLBACK to comm2; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +COMMIT; +-- TRYING TO CHANGE FLAG 'IS_TRANSACTIONAL' +SELECT pgv_set('vars', 'any1', 'value'::text); +ERROR: variable "any1" already created as TRANSACTIONAL +SELECT pgv_set('vars', 'any2', 'value'::text, true); +ERROR: variable "any2" already created as NOT TRANSACTIONAL +SELECT pgv_set_int('vars', 'int1', 301); +ERROR: variable "int1" already created as TRANSACTIONAL +SELECT pgv_set_int('vars', 'int2', 302, true); +ERROR: variable "int2" already created as NOT TRANSACTIONAL +SELECT pgv_set_text('vars', 'str1', 's301'); +ERROR: variable "str1" already created as TRANSACTIONAL +SELECT pgv_set_text('vars', 'str2', 's302', true); +ERROR: variable "str2" already created as NOT TRANSACTIONAL +SELECT pgv_set_numeric('vars', 'num1', 3.01); +ERROR: variable "num1" already created as TRANSACTIONAL +SELECT pgv_set_numeric('vars', 'num2', 3.02, true); +ERROR: variable "num2" already created as NOT TRANSACTIONAL +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 20:00:00'); +ERROR: variable "ts1" already created as TRANSACTIONAL +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 21:00:00', true); +ERROR: variable "ts2" already created as NOT TRANSACTIONAL +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 20:00:00 GMT+01'); +ERROR: variable "tstz1" already created as TRANSACTIONAL +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 21:00:00 GMT+02', true); +ERROR: variable "tstz2" already created as NOT TRANSACTIONAL +SELECT pgv_set_date('vars', 'd1', '2016-04-29'); +ERROR: variable "d1" already created as TRANSACTIONAL +SELECT pgv_set_date('vars', 'd2', '2016-04-30', true); +ERROR: variable "d2" already created as NOT TRANSACTIONAL +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo2", null]'); +ERROR: variable "j1" already created as TRANSACTIONAL +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz2", "balance": 7.77, "active": true}', true); +ERROR: variable "j2" already created as NOT TRANSACTIONAL +SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str66' :: varchar)); +ERROR: variable "r1" already created as TRANSACTIONAL +SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str66' :: varchar),true); +ERROR: variable "r2" already created as NOT TRANSACTIONAL +-- CHECK pgv_list() WHILE WE HAVE A LOT OF MISCELLANEOUS VARIABLES +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+---------+------------------ + vars | any1 | t + vars | any2 | f + vars | d1 | t + vars | d2 | f + vars | int1 | t + vars | int2 | f + vars | intNULL | t + vars | num1 | t + vars | num2 | f + vars | str1 | t + vars | str2 | f + vars | ts1 | t + vars | ts2 | f + vars | tstz1 | t + vars | tstz2 | f + vars2 | j1 | t + vars2 | j2 | f + vars3 | r1 | t + vars3 | r2 | f +(19 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- VARIABLES DECLARED IN SUBTRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK TO SAVEPOINT +-- For better readability we don't use deprecated api functions in test below +BEGIN; +SAVEPOINT sp_to_rollback; +SELECT pgv_set('vars', 'any1', 'text value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'text value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str44' :: varchar), true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str44' :: varchar)); + pgv_insert +------------ + +(1 row) + +ROLLBACK TO sp_to_rollback; +COMMIT; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized variable "any1" +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +------------ + text value +(1 row) + +SELECT pgv_select('vars3', 'r1'); +ERROR: unrecognized variable "r1" +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (6,str44) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION +BEGIN; +SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------------- + after savepoint sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------------- + before savepoint sp1 +(1 row) + +COMMIT; +BEGIN; +SAVEPOINT sp1; +SAVEPOINT sp2; +SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars2', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +ROLLBACK TO sp1; +COMMIT; +SELECT pgv_get('vars2', 'any1',NULL::text); +ERROR: unrecognized package "vars2" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--CHECK TRANSACTION COMMIT +-- Declare variables +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'some value'::text); + pgv_set +--------- + +(1 row) + +BEGIN; +-- Set new values +SELECT pgv_set('vars', 'any1', 'another value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'another value'::text); + pgv_set +--------- + +(1 row) + +-- Check values before committing transaction +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +-- Check values after committing transaction +COMMIT; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SELECT pgv_insert('vars3', 'r2', tab) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +BEGIN; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +COMMIT; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +-- CHECK TRANSACTION ROLLBACK +-- Variables are already declared +BEGIN; +-- Set new values +SELECT pgv_set('vars', 'any1', 'one more value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'one more value'::text); + pgv_set +--------- + +(1 row) + +-- Check values before rollback +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +-- Check values after rollback +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +-- Record variables +BEGIN; +SELECT pgv_delete('vars3', 'r1', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_delete('vars3', 'r2', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +ROLLBACK; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- VARIABLES DECLARED IN TRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK +BEGIN; +SELECT pgv_set('vars', 'any1', 'text value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'text value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_insert('vars', 'r1', row(6 :: integer, 'str44' :: varchar), true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r2', row(6 :: integer, 'str44' :: varchar)); + pgv_insert +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized variable "any1" +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +------------ + text value +(1 row) + +SELECT pgv_select('vars', 'r1'); +ERROR: unrecognized variable "r1" +SELECT pgv_select('vars', 'r2'); + pgv_select +------------ + (6,str44) +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +-- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION +SELECT pgv_set('vars', 'any1', 'before transaction block'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------------- + after savepoint sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------------- + before savepoint sp1 +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +-------------------------- + before transaction block +(1 row) + +BEGIN; +SAVEPOINT sp1; +SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp1; +SELECT pgv_get('vars2', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +ROLLBACK; +SELECT pgv_get('vars2', 'any1',NULL::text); +ERROR: unrecognized package "vars2" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Additional tests +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +BEGIN; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'before savepoint sp1' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_update('vars3', 'r1', row(5 :: integer, 'after savepoint sp1' :: varchar)); + pgv_update +------------ + t +(1 row) + +SAVEPOINT sp2; +SELECT pgv_insert('vars3', 'r1', row(7 :: integer, 'row after sp2 to remove in sp4' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT sp3; +SAVEPOINT sp4; +SELECT pgv_delete('vars3', 'r1', 7); + pgv_delete +------------ + t +(1 row) + +SAVEPOINT sp5; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +ROLLBACK TO sp5; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +RELEASE sp4; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +ROLLBACK TO sp3; +SELECT pgv_select('vars3', 'r1'); + pgv_select +-------------------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) + (7,"row after sp2 to remove in sp4") +(6 rows) + +RELEASE sp2; +SELECT pgv_select('vars3', 'r1'); + pgv_select +-------------------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) + (7,"row after sp2 to remove in sp4") +(6 rows) + +ROLLBACK TO sp1; +SELECT pgv_select('vars3', 'r1'); + pgv_select +---------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"before savepoint sp1") + (0,str00) +(5 rows) + +COMMIT; +SELECT pgv_select('vars3', 'r1'); + pgv_select +---------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"before savepoint sp1") + (0,str00) +(5 rows) + +SELECT pgv_set('vars', 'any1', 'outer'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'begin'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'sp2'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp3; +SAVEPOINT sp4; +SELECT pgv_set('vars', 'any1', 'sp4'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp5; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +ROLLBACK TO sp5; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +RELEASE sp4; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +ROLLBACK TO sp3; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp2 +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + begin +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + outer +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'wrong type'::varchar, true); +ERROR: variable "any1" requires "text" value +COMMIT; +-- THE REMOVAL OF THE VARIABLE MUST BE CANCELED ON ROLLBACK +SELECT pgv_set('vars', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +ROLLBACK; +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + t +(1 row) + +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +BEGIN; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +COMMIT; +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized package "vars" +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ + vars3 | r1 | t +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ + vars3 | r1 | t +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +COMMIT; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'regular', 'regular variable exists'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'trans1', 'trans1 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_free(); -- Check sequential package removal in one subtransaction + pgv_free +---------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'trans2', 'trans2 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans2 | t +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +ROLLBACK; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans1 | t +(1 row) + +BEGIN; +SAVEPOINT sp1; +SAVEPOINT sp2; +SAVEPOINT sp3; +SELECT pgv_set('vars2', 'trans2', 'trans2 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp4; +SAVEPOINT sp5; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +RELEASE sp5; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +RELEASE sp4; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +BEGIN; +SELECT pgv_set('vars', 'trans1', 'package created'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'trans1', 'package restored'::text, true); + pgv_set +--------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans1 | t +(1 row) + +COMMIT; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +-- REMOVED TRANSACTIONAL VARIABLE SHOULD BE NOT ACCESSIBLE THROUGH LastVariable +SELECT pgv_insert('package', 'errs',row(n), true) +FROM generate_series(1,5) AS gs(n) WHERE 1.0/(n-3)<>0; +ERROR: division by zero +SELECT pgv_insert('package', 'errs',row(1), true); + pgv_insert +------------ + +(1 row) + +-- Variable should not exists in case when error occurs during creation +SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); +ERROR: could not identify a hash function for type unknown +SELECT pgv_select('vars4', 'r1', 0); +ERROR: unrecognized package "vars4" +-- If variable created and removed in same transaction level, +-- it should be totally removed and should not be present +-- in changes list and cache. +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT comm; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +RELEASE comm; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized package "vars" +COMMIT; +-- Tests for PGPRO-2440 +SELECT pgv_insert('vars3', 'r3', row(1 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +BEGIN; +SELECT pgv_insert('vars3', 'r3', row(2 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT comm; +SELECT pgv_insert('vars3', 'r3', row(3 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +COMMIT; +SELECT pgv_delete('vars3', 'r3', 3); + pgv_delete +------------ + t +(1 row) + +BEGIN; +SELECT pgv_set('vars1', 't1', ''::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars2', 't2', ''::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SAVEPOINT sp2; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ERROR; +ERROR: syntax error at or near "ERROR" +LINE 1: ERROR; + ^ +COMMIT; +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SAVEPOINT sp_to_rollback; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +ROLLBACK TO sp_to_rollback; +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +-- Package should exist after rollback if it contains regular variable +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text); + pgv_set +--------- + +(1 row) + +ROLLBACK; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars +(1 row) + +-- Package should not exist if it becomes empty in rolled back transaction +BEGIN; +SAVEPOINT comm2; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +ROLLBACK TO comm2; +SELECT pgv_exists('vars'); + pgv_exists +------------ + f +(1 row) + +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars +(1 row) + +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +SELECT pgv_set('vars', 'any1', 'some value'::text); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Variables should be insertable after pgv_remove (variable) +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | x | t +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +-- Variables should be insertable after pgv_remove (package) +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | x | t +(1 row) + +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | y | t +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +-- Variables should be insertable after pgv_free +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | y | t +(1 row) + +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | z | t +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Variables should be rollbackable if transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +--- +--- Variables should not be rollbackable if not transactional +--- +-- case 1 (remove var) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 2 (remove pack) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 3 (free) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- clear all +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #1 (remove var) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "y" +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #2 (remove pack) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #3 (free) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #4 +--- +-- non transactional, remove var +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, remove pac +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, free +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional, remove var +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, remove pack +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, free +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #5 +--- +-- non transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +--- +--- Cursor test #6 +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +COMMIT; +--- +--- Tests for "leaked hash_seq_search scan for hash table" +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +--- +--- Some special cases +--- +-- take #1 +SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +SELECT pgv_remove('test', 'z1'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "z1" +ROLLBACK; +SELECT pgv_select('test', 'z1'); + pgv_select +------------ + (2,2) +(1 row) + +-- take #2 +SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +SELECT pgv_remove('test', 'z2'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "z2" +ROLLBACK; +SELECT pgv_select('test', 'z2'); +ERROR: unrecognized variable "z2" +SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +-- take #3 +SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'z3'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "z3" +ROLLBACK; +SELECT pgv_select('test', 'z3'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'z3'); + pgv_remove +------------ + +(1 row) + +COMMIT; +SELECT pgv_select('test', 'z3'); +ERROR: unrecognized variable "z3" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- take #4 +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +SAVEPOINT sp1; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +--- +--- Test cases for pgv_stats +--- +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); +ERROR: there is a record in the variable "y" with same key +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); +ERROR: variable "x" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/pg_variables.c b/pg_variables.c index ee1fa3d..9e83352 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -129,6 +129,165 @@ static ExecutorEnd_hook_type prev_ExecutorEnd = NULL; static dlist_head *changesStack = NULL; static MemoryContext changesStackContext = NULL; +/* + * List to store all the running hash_seq_search, variable and package scan for + * hash table. + * + * NOTE: In function variable_select we use hash_seq_search to find next tuple. + * So, in case user do not get all the data from set at once (use cursors or + * LIMIT) we have to call hash_seq_term to not to leak hash_seq_search scans. + * + * For doing this, we alloc all of the rstats in the TopTransactionContext and + * save pointers to the rstats into list. Once transaction ended (commited or + * aborted) we clear all the "active" hash_seq_search by calling hash_seq_term. + * + * TopTransactionContext is handy here, because it would not be reset by the + * time pgvTransCallback is called. + */ +static List *variables_stats = NIL; +static List *packages_stats = NIL; + +typedef struct tagHtabToStat { + HTAB *hash; + HASH_SEQ_STATUS *status; + Variable *variable; + Package *package; + int level; +} HtabToStat; + +/* + * A bunch of comp functions for HtabToStat members here. + */ +static bool +HtabToStat_status_eq(HtabToStat *entry, void *value) +{ + return entry->status == (HASH_SEQ_STATUS *) value; +} + +static bool +HtabToStat_variable_eq(HtabToStat *entry, void *value) +{ + return entry->variable == (Variable *) value; +} + +static bool +HtabToStat_package_eq(HtabToStat *entry, void *value) +{ + return entry->package == (Package *) value; +} + +static bool +HtabToStat_eq_all(HtabToStat *entry, void *value) +{ + return true; +} + +static bool +HtabToStat_level_eq(HtabToStat *entry, void *value) +{ + return entry->level == *(int *) value; +} + +/* + * Generic remove_if algorithm for HtabToStat. + * + * 'eq' - is a function pointer used to compare list entries to the 'value'. + * 'match_first' - if true return on first match. + */ +static void +HtabToStat_remove_if(List **l, void *value, + bool (*eq)(HtabToStat *, void *), + bool match_first) +{ +#if (PG_VERSION_NUM < 130000) + ListCell *cell, *next, *prev = NULL; + HtabToStat *entry = NULL; + + for (cell = list_head(*l); cell; cell = next) + { + entry = (HtabToStat *) lfirst(cell); + next = lnext(cell); + + if (eq(entry, value)) + { + *l = list_delete_cell(*l, cell, prev); + pfree(entry->status); + pfree(entry); + + if (match_first) + return; + } + else + { + prev = cell; + } + } +#else + /* + * See https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=1cff1b95ab6ddae32faa3efe0d95a820dbfdc164 + * + * Version > 13 have different lists interface. + */ + ListCell *cell; + HtabToStat *entry = NULL; + + foreach(cell, *l) + { + entry = (HtabToStat *) lfirst(cell); + + if (eq(entry, value)) + *l = foreach_delete_current(*l, cell); + } +#endif +} + +/* + * Remove first entry for status. + */ +static void +remove_variables_status(List **l, HASH_SEQ_STATUS *status) +{ + HtabToStat_remove_if(l, status, HtabToStat_status_eq, true); +} + +/* + * Remove first entry for variable. + */ +static void +remove_variables_variable(List **l, Variable *variable) +{ + HtabToStat_remove_if(l, variable, HtabToStat_variable_eq, true); +} + +/* + * Remove all the entries for package. + */ +static void +remove_variables_package(List **l, Package *package) +{ + HtabToStat_remove_if(l, package, HtabToStat_package_eq, false); +} + +/* + * Remove all the entries for level. + */ +static void +remove_variables_level(List **l, int level) +{ + HtabToStat_remove_if(l, &level, HtabToStat_level_eq, false); +} + +/* + * Remove all. + */ +static void +remove_variables_all(List **l) +{ + HtabToStat_remove_if(l, NULL, HtabToStat_eq_all, false); + *l = NIL; +} + +static void freeStatsLists(void); /* Returns a lists of packages and variables changed at current subxact level */ #define get_actual_changes_list() \ ( \ @@ -595,30 +754,31 @@ variable_select(PG_FUNCTION_ARGS) FuncCallContext *funcctx; HASH_SEQ_STATUS *rstat; HashRecordEntry *item; + text *package_name; + text *var_name; + Package *package; + Variable *variable; - if (SRF_IS_FIRSTCALL()) - { - text *package_name; - text *var_name; - Package *package; - Variable *variable; - MemoryContext oldcontext; - RecordVar *record; + CHECK_ARGS_FOR_NULL(); - CHECK_ARGS_FOR_NULL(); + /* Get arguments */ + package_name = PG_GETARG_TEXT_PP(0); + var_name = PG_GETARG_TEXT_PP(1); - /* Get arguments */ - package_name = PG_GETARG_TEXT_PP(0); - var_name = PG_GETARG_TEXT_PP(1); + package = getPackage(package_name, true); + variable = getVariableInternal(package, var_name, RECORDOID, true, + true); - package = getPackage(package_name, true); - variable = getVariableInternal(package, var_name, RECORDOID, true, - true); + if (SRF_IS_FIRSTCALL()) + { + MemoryContext oldcontext; + RecordVar *record; + HtabToStat *htab_to_stat; record = &(GetActualValue(variable).record); - funcctx = SRF_FIRSTCALL_INIT(); - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + oldcontext = MemoryContextSwitchTo(TopTransactionContext); funcctx->tuple_desc = record->tupdesc; @@ -626,6 +786,14 @@ variable_select(PG_FUNCTION_ARGS) hash_seq_init(rstat, record->rhash); funcctx->user_fctx = rstat; + htab_to_stat = palloc0(sizeof(HtabToStat)); + htab_to_stat->hash = record->rhash; + htab_to_stat->status = rstat; + htab_to_stat->variable = variable; + htab_to_stat->package = package; + htab_to_stat->level = GetCurrentTransactionNestLevel(); + variables_stats = lcons((void *)htab_to_stat, variables_stats); + MemoryContextSwitchTo(oldcontext); PG_FREE_IF_COPY(package_name, 0); PG_FREE_IF_COPY(var_name, 1); @@ -645,7 +813,7 @@ variable_select(PG_FUNCTION_ARGS) } else { - pfree(rstat); + remove_variables_status(&variables_stats, rstat); SRF_RETURN_DONE(funcctx); } } @@ -947,6 +1115,8 @@ remove_package(PG_FUNCTION_ARGS) resetVariablesCache(); + remove_variables_package(&variables_stats, package); + PG_FREE_IF_COPY(package_name, 0); PG_RETURN_VOID(); } @@ -1042,6 +1212,7 @@ remove_packages(PG_FUNCTION_ARGS) } resetVariablesCache(); + remove_variables_all(&variables_stats); PG_RETURN_VOID(); } @@ -1213,7 +1384,7 @@ get_packages_stats(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; MemoryContext oldcontext; - HASH_SEQ_STATUS *pstat; + HASH_SEQ_STATUS *rstat; Package *package; if (SRF_IS_FIRSTCALL()) @@ -1238,11 +1409,16 @@ get_packages_stats(PG_FUNCTION_ARGS) */ if (packagesHash) { - pstat = (HASH_SEQ_STATUS *) palloc0(sizeof(HASH_SEQ_STATUS)); + MemoryContext ctx; + + ctx = MemoryContextSwitchTo(TopTransactionContext); + rstat = (HASH_SEQ_STATUS *) palloc0(sizeof(HASH_SEQ_STATUS)); /* Get packages list */ - hash_seq_init(pstat, packagesHash); + hash_seq_init(rstat, packagesHash); - funcctx->user_fctx = pstat; + funcctx->user_fctx = rstat; + packages_stats = lcons((void *)rstat, packages_stats); + MemoryContextSwitchTo(ctx); } else funcctx->user_fctx = NULL; @@ -1255,9 +1431,9 @@ get_packages_stats(PG_FUNCTION_ARGS) SRF_RETURN_DONE(funcctx); /* Get packages list */ - pstat = (HASH_SEQ_STATUS *) funcctx->user_fctx; + rstat = (HASH_SEQ_STATUS *) funcctx->user_fctx; - package = (Package *) hash_seq_search(pstat); + package = (Package *) hash_seq_search(rstat); if (package != NULL) { Datum values[2]; @@ -1289,7 +1465,8 @@ get_packages_stats(PG_FUNCTION_ARGS) } else { - pfree(pstat); + packages_stats = list_delete(packages_stats, rstat); + pfree(rstat); SRF_RETURN_DONE(funcctx); } } @@ -1749,6 +1926,7 @@ removeObject(TransObject *object, TransObjectType type) /* Remove object from hash table */ hash_search(hash, object->name, HASH_REMOVE, &found); + remove_variables_variable(&variables_stats, (Variable *) object); /* Remove package if it became empty */ if (type == TRANS_VARIABLE && isPackageEmpty(package)) @@ -2168,6 +2346,8 @@ pgvSubTransCallback(SubXactEvent event, SubTransactionId mySubid, break; } } + + remove_variables_level(&variables_stats, GetCurrentTransactionNestLevel()); } /* @@ -2197,6 +2377,9 @@ pgvTransCallback(XactEvent event, void *arg) break; } } + + if (event == XACT_EVENT_PRE_COMMIT || event == XACT_EVENT_ABORT) + freeStatsLists(); } /* @@ -2209,6 +2392,35 @@ variable_ExecutorEnd(QueryDesc *queryDesc) prev_ExecutorEnd(queryDesc); else standard_ExecutorEnd(queryDesc); + + freeStatsLists(); +} + +/* + * Free hash_seq_search scans + */ +static void +freeStatsLists(void) +{ + ListCell *cell; + HASH_SEQ_STATUS *status; + HtabToStat *htab_to_stat; + + foreach(cell, variables_stats) + { + htab_to_stat = (HtabToStat *) lfirst(cell); + hash_seq_term(htab_to_stat->status); + } + + variables_stats = NIL; + + foreach(cell, packages_stats) + { + status = (HASH_SEQ_STATUS *) lfirst(cell); + hash_seq_term(status); + } + + packages_stats = NIL; } /* diff --git a/sql/pg_variables_trans.sql b/sql/pg_variables_trans.sql index c4b8c90..2b83ab5 100644 --- a/sql/pg_variables_trans.sql +++ b/sql/pg_variables_trans.sql @@ -614,3 +614,464 @@ SELECT * FROM pgv_list() order by package, name; SELECT pgv_select('test', 'z'); SELECT pgv_free(); + +-- Variables should be rollbackable if transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); +SELECT pgv_select('test', 'x'); + +BEGIN; +SELECT pgv_remove('test', 'x'); +ROLLBACK; + +SELECT pgv_select('test', 'x'); + +BEGIN; +SELECT pgv_remove('test'); +ROLLBACK; + +SELECT pgv_select('test', 'x'); + +BEGIN; +SELECT pgv_free(); +ROLLBACK; + +SELECT pgv_select('test', 'x'); + +--- +--- Variables should not be rollbackable if not transactional +--- +-- case 1 (remove var) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); +SELECT pgv_select('test', 'y'); + +BEGIN; +SELECT pgv_remove('test', 'y'); +ROLLBACK; + +SELECT pgv_select('test', 'y'); +-- case 2 (remove pack) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); +SELECT pgv_select('test', 'y'); + +BEGIN; +SELECT pgv_remove('test'); +ROLLBACK; + +SELECT pgv_select('test', 'y'); +-- case 3 (free) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); +SELECT pgv_select('test', 'y'); + +BEGIN; +SELECT pgv_free(); +ROLLBACK; + +SELECT pgv_select('test', 'y'); +-- clear all +SELECT pgv_free(); + +--- +--- Cursors test #1 (remove var) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'y'); + +SELECT pgv_free(); +--- +--- Cursors test #2 (remove pack) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test'); + +SELECT pgv_free(); +--- +--- Cursors test #3 (free) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test'); + +SELECT pgv_free(); +--- +--- Cursor test #4 +--- + +-- non transactional, remove var +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +-- non transactional, remove pac +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +-- non transactional, free +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +-- transactional, remove var +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'y'); + +-- transactional, remove pack +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'y'); + +-- transactional, free +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'y'); + +SELECT pgv_free(); +--- +--- Cursor test #5 +--- + +-- non transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test', 'x'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +SELECT pgv_free(); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +-- transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test', 'x'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +SELECT pgv_free(); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +--- +--- Cursor test #6 +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test', 'x'); +COMMIT; + +--- +--- Tests for "leaked hash_seq_search scan for hash table" +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); +SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); +SELECT pgv_select('test', 'x') LIMIT 1; +SELECT pgv_select('test', 'x') LIMIT 2; +SELECT pgv_select('test', 'x') LIMIT 3; +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; +SELECT pgv_select('test', 'x') LIMIT 2; +SELECT pgv_select('test', 'x') LIMIT 3; +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; +SELECT pgv_select('test', 'x') LIMIT 2; +SELECT pgv_select('test', 'x') LIMIT 3; +COMMIT; + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); +SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); +SELECT pgv_select('test', 'y') LIMIT 1; +SELECT pgv_select('test', 'y') LIMIT 2; +SELECT pgv_select('test', 'y') LIMIT 3; +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; +SELECT pgv_select('test', 'y') LIMIT 2; +SELECT pgv_select('test', 'y') LIMIT 3; +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; +SELECT pgv_select('test', 'y') LIMIT 2; +SELECT pgv_select('test', 'y') LIMIT 3; +COMMIT; + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +FETCH 1 in r3_cur; +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; +FETCH 2 in r2_cur; +FETCH 2 in r3_cur; +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; +FETCH 3 in r2_cur; +FETCH 3 in r3_cur; +ROLLBACK; + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +FETCH 1 in r3_cur; +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; +FETCH 2 in r2_cur; +FETCH 2 in r3_cur; +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; +FETCH 3 in r2_cur; +FETCH 3 in r3_cur; +COMMIT; + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +FETCH 2 in r2_cur; +FETCH 3 in r3_cur; +ROLLBACK; + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +FETCH 2 in r2_cur; +FETCH 3 in r3_cur; +COMMIT; + +--- +--- Some special cases +--- +-- take #1 +SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test', 'z1'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'z1'); +-- take #2 +SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test', 'z2'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'z2'); +SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); +-- take #3 +SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test', 'z3'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'z3'); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test', 'z3'); +COMMIT; +SELECT pgv_select('test', 'z3'); + +SELECT pgv_free(); +-- take #4 +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 1 in r1_cur; +ROLLBACK TO SAVEPOINT sp1; +COMMIT; + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 2 in r1_cur; +ROLLBACK TO SAVEPOINT sp1; +COMMIT; + +BEGIN; +SAVEPOINT sp1; +SELECT pgv_select('test', 'x') LIMIT 1; +ROLLBACK TO SAVEPOINT sp1; +COMMIT; + +--- +--- Test cases for pgv_stats +--- +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +COMMIT; + +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +ROLLBACK; + +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); + +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +COMMIT; + +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +ROLLBACK; + +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); + +SELECT pgv_free(); From 3aa4c56b1190bb3d346c4bed76676c7981d2ba82 Mon Sep 17 00:00:00 2001 From: Alexey Kondratov Date: Fri, 13 Nov 2020 20:02:00 +0300 Subject: [PATCH 08/46] Bugfix/issue 27 (#31) * Issue #27: Error with transactional pgv_insert/pgv_remove * Issue #27: Error with transactional pgv_insert/pgv_remove - review * Issue #27: Add fix and improve tests. * Issue #27: Fix for backend termination on transaction commit. * Issue #27: Add fix for leaked hash_seq_search. Fix warning: leaked hash_seq_search scan for hash table. * Issue #27: Add tests and comment. * Issue #27: Add fix for leaked hash_seq_search for pgv_stats. * Issue #27: Add fix for VALGRING failed test. * Issue #27: Add fix for Travis Ci failed tests. * Issue #27: Fix tests for pgv_stats on 9.5 * Fix some comments * Issue #27: Fix list remove generic algo. * Issue #27: Fix savepoint in transaction issue. * Issue #27: Fix savepoint in transaction issue, add sql. * Issue #27: Fix savepoint in transaction issue, add expected result for 9 and 10. * Issue #27: Fix savepoint in transaction issue, add expected result for 9.5. * Issue #27: refactoring. + use uniform algorithm for status lists + rename struct tagHtabToStat to tagVariableStatEntry + use context instead of bunch of args in list workaround routines * Issue #27: Make sanitizer happy. At the moment pg_variables can't handle cursors in a "proper" way. It's possible to remove pg_variables while have active cursor open, which seem to be erratic and couse sanitizer to be unpappy about it. * Issue #27: Improve compatibility check. + Compatibility check for Postgres Professional Enterprise. + Fix for cursors: switch off hash leak message. + Switch off cursor test, because cursors not supported completely. * Issue #27: Make sanitizer happy. Sanitizer did failed on query like "SELECT pgv_select(...) LIMIT 1" * Issue #27: Fix fail under sanitizer with connoll. * Issue #27: Improve compatibility check. Use pg_compatibility_check_no_error function to precheck compatibility in order to free memory. Co-authored-by: Maxim Orlov --- expected/pg_variables_trans.out | 1395 +++++++++++ expected/pg_variables_trans_1.out | 3764 +++++++++++++++++++++++++++++ expected/pg_variables_trans_2.out | 3764 +++++++++++++++++++++++++++++ pg_variables.c | 470 +++- sql/pg_variables_trans.sql | 519 ++++ 5 files changed, 9881 insertions(+), 31 deletions(-) create mode 100644 expected/pg_variables_trans_1.out create mode 100644 expected/pg_variables_trans_2.out diff --git a/expected/pg_variables_trans.out b/expected/pg_variables_trans.out index d73ef69..8113fc8 100644 --- a/expected/pg_variables_trans.out +++ b/expected/pg_variables_trans.out @@ -2367,3 +2367,1398 @@ SELECT pgv_free(); (1 row) +-- Variables should be rollbackable if transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +--- +--- Variables should not be rollbackable if not transactional +--- +-- case 1 (remove var) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 2 (remove pack) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 3 (free) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- clear all +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #1 (remove var) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "y" +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #2 (remove pack) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #3 (free) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #4 +--- +-- non transactional, remove var +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, remove pac +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, free +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional, remove var +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, remove pack +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, free +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #5 +--- +-- non transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +--- +--- Cursor test #6 +--- +--SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +--BEGIN; +--DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +--FETCH 1 in r1_cur; +--CLOSE r1_cur; +--SELECT pgv_remove('test', 'x'); +--COMMIT; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Tests for "leaked hash_seq_search scan for hash table" +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +--- +--- Some special cases +--- +-- take #1 +SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +SELECT pgv_remove('test', 'z1'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "z1" +ROLLBACK; +SELECT pgv_select('test', 'z1'); + pgv_select +------------ + (2,2) +(1 row) + +-- take #2 +SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'z2'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: cursor "r1_cur" does not exist +ROLLBACK; +SELECT pgv_select('test', 'z2'); +ERROR: unrecognized variable "z2" +SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +-- take #3 +SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'z3'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: cursor "r1_cur" does not exist +ROLLBACK; +SELECT pgv_select('test', 'z3'); + pgv_select +------------ + (1,2) +(1 row) + +--BEGIN; +--DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +--FETCH 1 in r1_cur; +--SELECT pgv_remove('test', 'z3'); +--COMMIT; +--SELECT pgv_select('test', 'z3'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- take #4 +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +SAVEPOINT sp1; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +--- +--- Test cases for pgv_stats +--- +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); +ERROR: there is a record in the variable "y" with same key +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); +ERROR: variable "x" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Some special cases +--- +-- 1 +BEGIN; +SAVEPOINT comm2; +SELECT pgv_insert('test', 'x1', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +COMMIT; +-- 2 +BEGIN; +SELECT pgv_insert('test', 'x2', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +SAVEPOINT comm2; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,49152) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,49152) +(1 row) + +COMMIT; +-- 3 +BEGIN; +SELECT pgv_insert('test', 'x3', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +SAVEPOINT comm2; +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,65536) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,65536) +(1 row) + +COMMIT; +-- 4 +BEGIN; +SELECT pgv_insert('test', 'x4', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,81920) +(1 row) + +SAVEPOINT comm2; +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,81920) +(1 row) + +COMMIT; +-- 5 +BEGIN; +SELECT pgv_insert('test', 'x5', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,98304) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,98304) +(1 row) + +SAVEPOINT comm2; +COMMIT; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/expected/pg_variables_trans_1.out b/expected/pg_variables_trans_1.out new file mode 100644 index 0000000..b6f8132 --- /dev/null +++ b/expected/pg_variables_trans_1.out @@ -0,0 +1,3764 @@ +SET timezone = 'Europe/Moscow'; -- Need to proper output of datetime variables +--CHECK SAVEPOINT RELEASE +BEGIN; +-- Declare variables +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'some value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 101, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 102); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', NULL, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's101', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's102'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.01, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.02); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-03-30'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); + pgv_set_jsonb +--------------- + +(1 row) + +SAVEPOINT comm; +-- Set new values +SELECT pgv_set('vars', 'any1', 'another value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'another value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 103, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 103); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', 104, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's103', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's103'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.03, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.03); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 12:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 12:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 12:00:00 GMT+03', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 12:00:00 GMT+03'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-04-02', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-04-02'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'); + pgv_set_jsonb +--------------- + +(1 row) + +-- Check values before releasing savepoint +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +-- Check values after releasing savepoint +RELEASE comm; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +COMMIT; +CREATE TABLE tab (id int, t varchar); +INSERT INTO tab VALUES (0, 'str00'), (1, 'str33'), (2, NULL), (NULL, 'strNULL'); +BEGIN; +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SELECT pgv_insert('vars3', 'r2', tab) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SAVEPOINT comm; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +RELEASE comm; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +COMMIT; +--CHECK SAVEPOINT ROLLBACK +BEGIN; +-- Variables are already declared +SAVEPOINT comm2; +-- Set new values +SELECT pgv_set('vars', 'any1', 'one more value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'one more value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 101, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 102); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', NULL, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's101', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's102'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.01, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.02); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-03-30'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); + pgv_set_jsonb +--------------- + +(1 row) + +-- Check values before rollback to savepoint +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 101 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 102 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s101 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s102 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.01 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.02 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 10:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 11:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 14:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 16:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 03-29-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 03-30-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +--------------------- + [1, 2, "foo", null] +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +-------------------------------------------------- + {"bar": "baz", "active": false, "balance": 7.77} +(1 row) + +-- Check values after rollback to savepoint +ROLLBACK TO comm2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 102 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s102 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.02 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 11:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 16:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 03-30-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +-------------------------------------------------- + {"bar": "baz", "active": false, "balance": 7.77} +(1 row) + +COMMIT; +-- Record variables +BEGIN; +SAVEPOINT comm2; +SELECT pgv_delete('vars3', 'r1', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_delete('vars3', 'r2', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +ROLLBACK to comm2; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +COMMIT; +-- TRYING TO CHANGE FLAG 'IS_TRANSACTIONAL' +SELECT pgv_set('vars', 'any1', 'value'::text); +ERROR: variable "any1" already created as TRANSACTIONAL +SELECT pgv_set('vars', 'any2', 'value'::text, true); +ERROR: variable "any2" already created as NOT TRANSACTIONAL +SELECT pgv_set_int('vars', 'int1', 301); +ERROR: variable "int1" already created as TRANSACTIONAL +SELECT pgv_set_int('vars', 'int2', 302, true); +ERROR: variable "int2" already created as NOT TRANSACTIONAL +SELECT pgv_set_text('vars', 'str1', 's301'); +ERROR: variable "str1" already created as TRANSACTIONAL +SELECT pgv_set_text('vars', 'str2', 's302', true); +ERROR: variable "str2" already created as NOT TRANSACTIONAL +SELECT pgv_set_numeric('vars', 'num1', 3.01); +ERROR: variable "num1" already created as TRANSACTIONAL +SELECT pgv_set_numeric('vars', 'num2', 3.02, true); +ERROR: variable "num2" already created as NOT TRANSACTIONAL +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 20:00:00'); +ERROR: variable "ts1" already created as TRANSACTIONAL +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 21:00:00', true); +ERROR: variable "ts2" already created as NOT TRANSACTIONAL +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 20:00:00 GMT+01'); +ERROR: variable "tstz1" already created as TRANSACTIONAL +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 21:00:00 GMT+02', true); +ERROR: variable "tstz2" already created as NOT TRANSACTIONAL +SELECT pgv_set_date('vars', 'd1', '2016-04-29'); +ERROR: variable "d1" already created as TRANSACTIONAL +SELECT pgv_set_date('vars', 'd2', '2016-04-30', true); +ERROR: variable "d2" already created as NOT TRANSACTIONAL +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo2", null]'); +ERROR: variable "j1" already created as TRANSACTIONAL +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz2", "balance": 7.77, "active": true}', true); +ERROR: variable "j2" already created as NOT TRANSACTIONAL +SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str66' :: varchar)); +ERROR: variable "r1" already created as TRANSACTIONAL +SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str66' :: varchar),true); +ERROR: variable "r2" already created as NOT TRANSACTIONAL +-- CHECK pgv_list() WHILE WE HAVE A LOT OF MISCELLANEOUS VARIABLES +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+---------+------------------ + vars | any1 | t + vars | any2 | f + vars | d1 | t + vars | d2 | f + vars | int1 | t + vars | int2 | f + vars | intNULL | t + vars | num1 | t + vars | num2 | f + vars | str1 | t + vars | str2 | f + vars | ts1 | t + vars | ts2 | f + vars | tstz1 | t + vars | tstz2 | f + vars2 | j1 | t + vars2 | j2 | f + vars3 | r1 | t + vars3 | r2 | f +(19 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- VARIABLES DECLARED IN SUBTRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK TO SAVEPOINT +-- For better readability we don't use deprecated api functions in test below +BEGIN; +SAVEPOINT sp_to_rollback; +SELECT pgv_set('vars', 'any1', 'text value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'text value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str44' :: varchar), true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str44' :: varchar)); + pgv_insert +------------ + +(1 row) + +ROLLBACK TO sp_to_rollback; +COMMIT; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized variable "any1" +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +------------ + text value +(1 row) + +SELECT pgv_select('vars3', 'r1'); +ERROR: unrecognized variable "r1" +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (6,str44) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION +BEGIN; +SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------------- + after savepoint sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------------- + before savepoint sp1 +(1 row) + +COMMIT; +BEGIN; +SAVEPOINT sp1; +SAVEPOINT sp2; +SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars2', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +ROLLBACK TO sp1; +COMMIT; +SELECT pgv_get('vars2', 'any1',NULL::text); +ERROR: unrecognized package "vars2" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--CHECK TRANSACTION COMMIT +-- Declare variables +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'some value'::text); + pgv_set +--------- + +(1 row) + +BEGIN; +-- Set new values +SELECT pgv_set('vars', 'any1', 'another value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'another value'::text); + pgv_set +--------- + +(1 row) + +-- Check values before committing transaction +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +-- Check values after committing transaction +COMMIT; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SELECT pgv_insert('vars3', 'r2', tab) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +BEGIN; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +COMMIT; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +-- CHECK TRANSACTION ROLLBACK +-- Variables are already declared +BEGIN; +-- Set new values +SELECT pgv_set('vars', 'any1', 'one more value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'one more value'::text); + pgv_set +--------- + +(1 row) + +-- Check values before rollback +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +-- Check values after rollback +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +-- Record variables +BEGIN; +SELECT pgv_delete('vars3', 'r1', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_delete('vars3', 'r2', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +ROLLBACK; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- VARIABLES DECLARED IN TRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK +BEGIN; +SELECT pgv_set('vars', 'any1', 'text value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'text value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_insert('vars', 'r1', row(6 :: integer, 'str44' :: varchar), true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r2', row(6 :: integer, 'str44' :: varchar)); + pgv_insert +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized variable "any1" +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +------------ + text value +(1 row) + +SELECT pgv_select('vars', 'r1'); +ERROR: unrecognized variable "r1" +SELECT pgv_select('vars', 'r2'); + pgv_select +------------ + (6,str44) +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +-- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION +SELECT pgv_set('vars', 'any1', 'before transaction block'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------------- + after savepoint sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------------- + before savepoint sp1 +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +-------------------------- + before transaction block +(1 row) + +BEGIN; +SAVEPOINT sp1; +SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp1; +SELECT pgv_get('vars2', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +ROLLBACK; +SELECT pgv_get('vars2', 'any1',NULL::text); +ERROR: unrecognized package "vars2" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Additional tests +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +BEGIN; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'before savepoint sp1' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_update('vars3', 'r1', row(5 :: integer, 'after savepoint sp1' :: varchar)); + pgv_update +------------ + t +(1 row) + +SAVEPOINT sp2; +SELECT pgv_insert('vars3', 'r1', row(7 :: integer, 'row after sp2 to remove in sp4' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT sp3; +SAVEPOINT sp4; +SELECT pgv_delete('vars3', 'r1', 7); + pgv_delete +------------ + t +(1 row) + +SAVEPOINT sp5; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +ROLLBACK TO sp5; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +RELEASE sp4; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +ROLLBACK TO sp3; +SELECT pgv_select('vars3', 'r1'); + pgv_select +-------------------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) + (7,"row after sp2 to remove in sp4") +(6 rows) + +RELEASE sp2; +SELECT pgv_select('vars3', 'r1'); + pgv_select +-------------------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) + (7,"row after sp2 to remove in sp4") +(6 rows) + +ROLLBACK TO sp1; +SELECT pgv_select('vars3', 'r1'); + pgv_select +---------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"before savepoint sp1") + (0,str00) +(5 rows) + +COMMIT; +SELECT pgv_select('vars3', 'r1'); + pgv_select +---------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"before savepoint sp1") + (0,str00) +(5 rows) + +SELECT pgv_set('vars', 'any1', 'outer'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'begin'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'sp2'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp3; +SAVEPOINT sp4; +SELECT pgv_set('vars', 'any1', 'sp4'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp5; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +ROLLBACK TO sp5; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +RELEASE sp4; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +ROLLBACK TO sp3; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp2 +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + begin +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + outer +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'wrong type'::varchar, true); +ERROR: variable "any1" requires "text" value +COMMIT; +-- THE REMOVAL OF THE VARIABLE MUST BE CANCELED ON ROLLBACK +SELECT pgv_set('vars', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +ROLLBACK; +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + t +(1 row) + +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +BEGIN; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +COMMIT; +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized package "vars" +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ + vars3 | r1 | t +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ + vars3 | r1 | t +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +COMMIT; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'regular', 'regular variable exists'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'trans1', 'trans1 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_free(); -- Check sequential package removal in one subtransaction + pgv_free +---------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'trans2', 'trans2 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans2 | t +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +ROLLBACK; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans1 | t +(1 row) + +BEGIN; +SAVEPOINT sp1; +SAVEPOINT sp2; +SAVEPOINT sp3; +SELECT pgv_set('vars2', 'trans2', 'trans2 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp4; +SAVEPOINT sp5; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +RELEASE sp5; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +RELEASE sp4; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +BEGIN; +SELECT pgv_set('vars', 'trans1', 'package created'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'trans1', 'package restored'::text, true); + pgv_set +--------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans1 | t +(1 row) + +COMMIT; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +-- REMOVED TRANSACTIONAL VARIABLE SHOULD BE NOT ACCESSIBLE THROUGH LastVariable +SELECT pgv_insert('package', 'errs',row(n), true) +FROM generate_series(1,5) AS gs(n) WHERE 1.0/(n-3)<>0; +ERROR: division by zero +SELECT pgv_insert('package', 'errs',row(1), true); + pgv_insert +------------ + +(1 row) + +-- Variable should not exists in case when error occurs during creation +SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); +ERROR: could not identify a hash function for type unknown +SELECT pgv_select('vars4', 'r1', 0); +ERROR: unrecognized package "vars4" +-- If variable created and removed in same transaction level, +-- it should be totally removed and should not be present +-- in changes list and cache. +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT comm; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +RELEASE comm; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized package "vars" +COMMIT; +-- Tests for PGPRO-2440 +SELECT pgv_insert('vars3', 'r3', row(1 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +BEGIN; +SELECT pgv_insert('vars3', 'r3', row(2 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT comm; +SELECT pgv_insert('vars3', 'r3', row(3 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +COMMIT; +SELECT pgv_delete('vars3', 'r3', 3); + pgv_delete +------------ + t +(1 row) + +BEGIN; +SELECT pgv_set('vars1', 't1', ''::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars2', 't2', ''::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SAVEPOINT sp2; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ERROR; +ERROR: syntax error at or near "ERROR" +LINE 1: ERROR; + ^ +COMMIT; +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SAVEPOINT sp_to_rollback; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +ROLLBACK TO sp_to_rollback; +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +-- Package should exist after rollback if it contains regular variable +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text); + pgv_set +--------- + +(1 row) + +ROLLBACK; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars +(1 row) + +-- Package should not exist if it becomes empty in rolled back transaction +BEGIN; +SAVEPOINT comm2; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +ROLLBACK TO comm2; +SELECT pgv_exists('vars'); + pgv_exists +------------ + f +(1 row) + +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars +(1 row) + +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +SELECT pgv_set('vars', 'any1', 'some value'::text); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Variables should be insertable after pgv_remove (variable) +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | x | t +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +-- Variables should be insertable after pgv_remove (package) +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | x | t +(1 row) + +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | y | t +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +-- Variables should be insertable after pgv_free +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | y | t +(1 row) + +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | z | t +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Variables should be rollbackable if transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +--- +--- Variables should not be rollbackable if not transactional +--- +-- case 1 (remove var) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 2 (remove pack) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 3 (free) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- clear all +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #1 (remove var) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "y" +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #2 (remove pack) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #3 (free) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #4 +--- +-- non transactional, remove var +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, remove pac +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, free +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional, remove var +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, remove pack +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, free +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #5 +--- +-- non transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +--- +--- Cursor test #6 +--- +--SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +--BEGIN; +--DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +--FETCH 1 in r1_cur; +--CLOSE r1_cur; +--SELECT pgv_remove('test', 'x'); +--COMMIT; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Tests for "leaked hash_seq_search scan for hash table" +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +--- +--- Some special cases +--- +-- take #1 +SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +SELECT pgv_remove('test', 'z1'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "z1" +ROLLBACK; +SELECT pgv_select('test', 'z1'); + pgv_select +------------ + (2,2) +(1 row) + +-- take #2 +SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'z2'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: cursor "r1_cur" does not exist +ROLLBACK; +SELECT pgv_select('test', 'z2'); +ERROR: unrecognized variable "z2" +SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +-- take #3 +SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'z3'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: cursor "r1_cur" does not exist +ROLLBACK; +SELECT pgv_select('test', 'z3'); + pgv_select +------------ + (1,2) +(1 row) + +--BEGIN; +--DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +--FETCH 1 in r1_cur; +--SELECT pgv_remove('test', 'z3'); +--COMMIT; +--SELECT pgv_select('test', 'z3'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- take #4 +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +SAVEPOINT sp1; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +--- +--- Test cases for pgv_stats +--- +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); +ERROR: there is a record in the variable "y" with same key +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); +ERROR: variable "x" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Some special cases +--- +-- 1 +BEGIN; +SAVEPOINT comm2; +SELECT pgv_insert('test', 'x1', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +COMMIT; +-- 2 +BEGIN; +SELECT pgv_insert('test', 'x2', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +SAVEPOINT comm2; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +COMMIT; +-- 3 +BEGIN; +SELECT pgv_insert('test', 'x3', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +SAVEPOINT comm2; +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +COMMIT; +-- 4 +BEGIN; +SELECT pgv_insert('test', 'x4', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +SAVEPOINT comm2; +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +COMMIT; +-- 5 +BEGIN; +SELECT pgv_insert('test', 'x5', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +----------- + (test,0) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +----------- + (test,0) +(1 row) + +SAVEPOINT comm2; +COMMIT; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/expected/pg_variables_trans_2.out b/expected/pg_variables_trans_2.out new file mode 100644 index 0000000..a07ad7d --- /dev/null +++ b/expected/pg_variables_trans_2.out @@ -0,0 +1,3764 @@ +SET timezone = 'Europe/Moscow'; -- Need to proper output of datetime variables +--CHECK SAVEPOINT RELEASE +BEGIN; +-- Declare variables +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'some value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 101, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 102); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', NULL, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's101', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's102'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.01, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.02); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-03-30'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); + pgv_set_jsonb +--------------- + +(1 row) + +SAVEPOINT comm; +-- Set new values +SELECT pgv_set('vars', 'any1', 'another value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'another value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 103, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 103); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', 104, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's103', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's103'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.03, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.03); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 12:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 12:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 12:00:00 GMT+03', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 12:00:00 GMT+03'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-04-02', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-04-02'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'); + pgv_set_jsonb +--------------- + +(1 row) + +-- Check values before releasing savepoint +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +-- Check values after releasing savepoint +RELEASE comm; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +COMMIT; +CREATE TABLE tab (id int, t varchar); +INSERT INTO tab VALUES (0, 'str00'), (1, 'str33'), (2, NULL), (NULL, 'strNULL'); +BEGIN; +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SELECT pgv_insert('vars3', 'r2', tab) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SAVEPOINT comm; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +RELEASE comm; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +COMMIT; +--CHECK SAVEPOINT ROLLBACK +BEGIN; +-- Variables are already declared +SAVEPOINT comm2; +-- Set new values +SELECT pgv_set('vars', 'any1', 'one more value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'one more value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 101, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 102); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', NULL, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's101', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's102'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.01, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.02); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-03-30'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); + pgv_set_jsonb +--------------- + +(1 row) + +-- Check values before rollback to savepoint +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 101 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 102 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s101 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s102 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.01 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.02 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 10:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 11:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 14:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 16:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 03-29-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 03-30-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +--------------------- + [1, 2, "foo", null] +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +-------------------------------------------------- + {"bar": "baz", "active": false, "balance": 7.77} +(1 row) + +-- Check values after rollback to savepoint +ROLLBACK TO comm2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 102 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s102 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.02 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 11:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 16:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 03-30-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +-------------------------------------------------- + {"bar": "baz", "active": false, "balance": 7.77} +(1 row) + +COMMIT; +-- Record variables +BEGIN; +SAVEPOINT comm2; +SELECT pgv_delete('vars3', 'r1', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_delete('vars3', 'r2', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +ROLLBACK to comm2; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +COMMIT; +-- TRYING TO CHANGE FLAG 'IS_TRANSACTIONAL' +SELECT pgv_set('vars', 'any1', 'value'::text); +ERROR: variable "any1" already created as TRANSACTIONAL +SELECT pgv_set('vars', 'any2', 'value'::text, true); +ERROR: variable "any2" already created as NOT TRANSACTIONAL +SELECT pgv_set_int('vars', 'int1', 301); +ERROR: variable "int1" already created as TRANSACTIONAL +SELECT pgv_set_int('vars', 'int2', 302, true); +ERROR: variable "int2" already created as NOT TRANSACTIONAL +SELECT pgv_set_text('vars', 'str1', 's301'); +ERROR: variable "str1" already created as TRANSACTIONAL +SELECT pgv_set_text('vars', 'str2', 's302', true); +ERROR: variable "str2" already created as NOT TRANSACTIONAL +SELECT pgv_set_numeric('vars', 'num1', 3.01); +ERROR: variable "num1" already created as TRANSACTIONAL +SELECT pgv_set_numeric('vars', 'num2', 3.02, true); +ERROR: variable "num2" already created as NOT TRANSACTIONAL +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 20:00:00'); +ERROR: variable "ts1" already created as TRANSACTIONAL +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 21:00:00', true); +ERROR: variable "ts2" already created as NOT TRANSACTIONAL +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 20:00:00 GMT+01'); +ERROR: variable "tstz1" already created as TRANSACTIONAL +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 21:00:00 GMT+02', true); +ERROR: variable "tstz2" already created as NOT TRANSACTIONAL +SELECT pgv_set_date('vars', 'd1', '2016-04-29'); +ERROR: variable "d1" already created as TRANSACTIONAL +SELECT pgv_set_date('vars', 'd2', '2016-04-30', true); +ERROR: variable "d2" already created as NOT TRANSACTIONAL +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo2", null]'); +ERROR: variable "j1" already created as TRANSACTIONAL +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz2", "balance": 7.77, "active": true}', true); +ERROR: variable "j2" already created as NOT TRANSACTIONAL +SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str66' :: varchar)); +ERROR: variable "r1" already created as TRANSACTIONAL +SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str66' :: varchar),true); +ERROR: variable "r2" already created as NOT TRANSACTIONAL +-- CHECK pgv_list() WHILE WE HAVE A LOT OF MISCELLANEOUS VARIABLES +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+---------+------------------ + vars | any1 | t + vars | any2 | f + vars | d1 | t + vars | d2 | f + vars | int1 | t + vars | int2 | f + vars | intNULL | t + vars | num1 | t + vars | num2 | f + vars | str1 | t + vars | str2 | f + vars | ts1 | t + vars | ts2 | f + vars | tstz1 | t + vars | tstz2 | f + vars2 | j1 | t + vars2 | j2 | f + vars3 | r1 | t + vars3 | r2 | f +(19 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- VARIABLES DECLARED IN SUBTRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK TO SAVEPOINT +-- For better readability we don't use deprecated api functions in test below +BEGIN; +SAVEPOINT sp_to_rollback; +SELECT pgv_set('vars', 'any1', 'text value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'text value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str44' :: varchar), true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str44' :: varchar)); + pgv_insert +------------ + +(1 row) + +ROLLBACK TO sp_to_rollback; +COMMIT; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized variable "any1" +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +------------ + text value +(1 row) + +SELECT pgv_select('vars3', 'r1'); +ERROR: unrecognized variable "r1" +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (6,str44) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION +BEGIN; +SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------------- + after savepoint sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------------- + before savepoint sp1 +(1 row) + +COMMIT; +BEGIN; +SAVEPOINT sp1; +SAVEPOINT sp2; +SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars2', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +ROLLBACK TO sp1; +COMMIT; +SELECT pgv_get('vars2', 'any1',NULL::text); +ERROR: unrecognized package "vars2" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--CHECK TRANSACTION COMMIT +-- Declare variables +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'some value'::text); + pgv_set +--------- + +(1 row) + +BEGIN; +-- Set new values +SELECT pgv_set('vars', 'any1', 'another value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'another value'::text); + pgv_set +--------- + +(1 row) + +-- Check values before committing transaction +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +-- Check values after committing transaction +COMMIT; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SELECT pgv_insert('vars3', 'r2', tab) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +BEGIN; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +COMMIT; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +-- CHECK TRANSACTION ROLLBACK +-- Variables are already declared +BEGIN; +-- Set new values +SELECT pgv_set('vars', 'any1', 'one more value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'one more value'::text); + pgv_set +--------- + +(1 row) + +-- Check values before rollback +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +-- Check values after rollback +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +-- Record variables +BEGIN; +SELECT pgv_delete('vars3', 'r1', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_delete('vars3', 'r2', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +ROLLBACK; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- VARIABLES DECLARED IN TRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK +BEGIN; +SELECT pgv_set('vars', 'any1', 'text value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'text value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_insert('vars', 'r1', row(6 :: integer, 'str44' :: varchar), true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r2', row(6 :: integer, 'str44' :: varchar)); + pgv_insert +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized variable "any1" +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +------------ + text value +(1 row) + +SELECT pgv_select('vars', 'r1'); +ERROR: unrecognized variable "r1" +SELECT pgv_select('vars', 'r2'); + pgv_select +------------ + (6,str44) +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +-- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION +SELECT pgv_set('vars', 'any1', 'before transaction block'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------------- + after savepoint sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------------- + before savepoint sp1 +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +-------------------------- + before transaction block +(1 row) + +BEGIN; +SAVEPOINT sp1; +SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp1; +SELECT pgv_get('vars2', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +ROLLBACK; +SELECT pgv_get('vars2', 'any1',NULL::text); +ERROR: unrecognized package "vars2" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Additional tests +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +BEGIN; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'before savepoint sp1' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_update('vars3', 'r1', row(5 :: integer, 'after savepoint sp1' :: varchar)); + pgv_update +------------ + t +(1 row) + +SAVEPOINT sp2; +SELECT pgv_insert('vars3', 'r1', row(7 :: integer, 'row after sp2 to remove in sp4' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT sp3; +SAVEPOINT sp4; +SELECT pgv_delete('vars3', 'r1', 7); + pgv_delete +------------ + t +(1 row) + +SAVEPOINT sp5; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +ROLLBACK TO sp5; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +RELEASE sp4; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +ROLLBACK TO sp3; +SELECT pgv_select('vars3', 'r1'); + pgv_select +-------------------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) + (7,"row after sp2 to remove in sp4") +(6 rows) + +RELEASE sp2; +SELECT pgv_select('vars3', 'r1'); + pgv_select +-------------------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) + (7,"row after sp2 to remove in sp4") +(6 rows) + +ROLLBACK TO sp1; +SELECT pgv_select('vars3', 'r1'); + pgv_select +---------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"before savepoint sp1") + (0,str00) +(5 rows) + +COMMIT; +SELECT pgv_select('vars3', 'r1'); + pgv_select +---------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"before savepoint sp1") + (0,str00) +(5 rows) + +SELECT pgv_set('vars', 'any1', 'outer'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'begin'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'sp2'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp3; +SAVEPOINT sp4; +SELECT pgv_set('vars', 'any1', 'sp4'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp5; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +ROLLBACK TO sp5; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +RELEASE sp4; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +ROLLBACK TO sp3; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp2 +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + begin +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + outer +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'wrong type'::varchar, true); +ERROR: variable "any1" requires "text" value +COMMIT; +-- THE REMOVAL OF THE VARIABLE MUST BE CANCELED ON ROLLBACK +SELECT pgv_set('vars', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +ROLLBACK; +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + t +(1 row) + +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +BEGIN; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +COMMIT; +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized package "vars" +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ + vars3 | r1 | t +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ + vars3 | r1 | t +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +COMMIT; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'regular', 'regular variable exists'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'trans1', 'trans1 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_free(); -- Check sequential package removal in one subtransaction + pgv_free +---------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'trans2', 'trans2 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans2 | t +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +ROLLBACK; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans1 | t +(1 row) + +BEGIN; +SAVEPOINT sp1; +SAVEPOINT sp2; +SAVEPOINT sp3; +SELECT pgv_set('vars2', 'trans2', 'trans2 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp4; +SAVEPOINT sp5; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +RELEASE sp5; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +RELEASE sp4; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +BEGIN; +SELECT pgv_set('vars', 'trans1', 'package created'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'trans1', 'package restored'::text, true); + pgv_set +--------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans1 | t +(1 row) + +COMMIT; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +-- REMOVED TRANSACTIONAL VARIABLE SHOULD BE NOT ACCESSIBLE THROUGH LastVariable +SELECT pgv_insert('package', 'errs',row(n), true) +FROM generate_series(1,5) AS gs(n) WHERE 1.0/(n-3)<>0; +ERROR: division by zero +SELECT pgv_insert('package', 'errs',row(1), true); + pgv_insert +------------ + +(1 row) + +-- Variable should not exists in case when error occurs during creation +SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); +ERROR: could not identify a hash function for type unknown +SELECT pgv_select('vars4', 'r1', 0); +ERROR: unrecognized package "vars4" +-- If variable created and removed in same transaction level, +-- it should be totally removed and should not be present +-- in changes list and cache. +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT comm; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +RELEASE comm; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized package "vars" +COMMIT; +-- Tests for PGPRO-2440 +SELECT pgv_insert('vars3', 'r3', row(1 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +BEGIN; +SELECT pgv_insert('vars3', 'r3', row(2 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT comm; +SELECT pgv_insert('vars3', 'r3', row(3 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +COMMIT; +SELECT pgv_delete('vars3', 'r3', 3); + pgv_delete +------------ + t +(1 row) + +BEGIN; +SELECT pgv_set('vars1', 't1', ''::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars2', 't2', ''::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SAVEPOINT sp2; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ERROR; +ERROR: syntax error at or near "ERROR" +LINE 1: ERROR; + ^ +COMMIT; +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SAVEPOINT sp_to_rollback; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +ROLLBACK TO sp_to_rollback; +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +-- Package should exist after rollback if it contains regular variable +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text); + pgv_set +--------- + +(1 row) + +ROLLBACK; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars +(1 row) + +-- Package should not exist if it becomes empty in rolled back transaction +BEGIN; +SAVEPOINT comm2; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +ROLLBACK TO comm2; +SELECT pgv_exists('vars'); + pgv_exists +------------ + f +(1 row) + +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars +(1 row) + +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +SELECT pgv_set('vars', 'any1', 'some value'::text); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Variables should be insertable after pgv_remove (variable) +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | x | t +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +-- Variables should be insertable after pgv_remove (package) +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | x | t +(1 row) + +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | y | t +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +-- Variables should be insertable after pgv_free +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | y | t +(1 row) + +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | z | t +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Variables should be rollbackable if transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +--- +--- Variables should not be rollbackable if not transactional +--- +-- case 1 (remove var) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 2 (remove pack) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 3 (free) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- clear all +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #1 (remove var) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "y" +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #2 (remove pack) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #3 (free) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #4 +--- +-- non transactional, remove var +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, remove pac +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, free +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional, remove var +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, remove pack +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, free +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #5 +--- +-- non transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +--- +--- Cursor test #6 +--- +--SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +--BEGIN; +--DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +--FETCH 1 in r1_cur; +--CLOSE r1_cur; +--SELECT pgv_remove('test', 'x'); +--COMMIT; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Tests for "leaked hash_seq_search scan for hash table" +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +--- +--- Some special cases +--- +-- take #1 +SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +SELECT pgv_remove('test', 'z1'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "z1" +ROLLBACK; +SELECT pgv_select('test', 'z1'); + pgv_select +------------ + (2,2) +(1 row) + +-- take #2 +SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'z2'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: cursor "r1_cur" does not exist +ROLLBACK; +SELECT pgv_select('test', 'z2'); +ERROR: unrecognized variable "z2" +SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +-- take #3 +SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'z3'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: cursor "r1_cur" does not exist +ROLLBACK; +SELECT pgv_select('test', 'z3'); + pgv_select +------------ + (1,2) +(1 row) + +--BEGIN; +--DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +--FETCH 1 in r1_cur; +--SELECT pgv_remove('test', 'z3'); +--COMMIT; +--SELECT pgv_select('test', 'z3'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- take #4 +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +SAVEPOINT sp1; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +--- +--- Test cases for pgv_stats +--- +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); +ERROR: there is a record in the variable "y" with same key +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); +ERROR: variable "x" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Some special cases +--- +-- 1 +BEGIN; +SAVEPOINT comm2; +SELECT pgv_insert('test', 'x1', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,24576) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,24576) +(1 row) + +COMMIT; +-- 2 +BEGIN; +SELECT pgv_insert('test', 'x2', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +SAVEPOINT comm2; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,40960) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,40960) +(1 row) + +COMMIT; +-- 3 +BEGIN; +SELECT pgv_insert('test', 'x3', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +SAVEPOINT comm2; +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,57344) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,57344) +(1 row) + +COMMIT; +-- 4 +BEGIN; +SELECT pgv_insert('test', 'x4', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,73728) +(1 row) + +SAVEPOINT comm2; +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,73728) +(1 row) + +COMMIT; +-- 5 +BEGIN; +SELECT pgv_insert('test', 'x5', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,90112) +(1 row) + +FETCH 1 in r2_cur; + pgv_stats +-------------- + (test,90112) +(1 row) + +SAVEPOINT comm2; +COMMIT; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/pg_variables.c b/pg_variables.c index ee1fa3d..4bd6bdd 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -10,11 +10,13 @@ #include "postgres.h" #include "fmgr.h" #include "funcapi.h" +#include "miscadmin.h" #include "access/htup_details.h" #include "access/xact.h" #include "catalog/pg_type.h" #include "parser/scansup.h" +#include "storage/proc.h" #include "utils/builtins.h" #include "utils/datum.h" #include "utils/lsyscache.h" @@ -129,6 +131,313 @@ static ExecutorEnd_hook_type prev_ExecutorEnd = NULL; static dlist_head *changesStack = NULL; static MemoryContext changesStackContext = NULL; +/* + * List to store all the running hash_seq_search, variable and package scan for + * hash table. + * + * NOTE: In function variable_select we use hash_seq_search to find next tuple. + * So, in case user do not get all the data from set at once (use cursors or + * LIMIT) we have to call hash_seq_term to not to leak hash_seq_search scans. + * + * For doing this, we alloc all of the rstats in the TopTransactionContext and + * save pointers to the rstats into list. Once transaction ended (commited or + * aborted) we clear all the "active" hash_seq_search by calling hash_seq_term. + * + * TopTransactionContext is handy here, because it would not be reset by the + * time pgvTransCallback is called. + */ +static List *variables_stats = NIL; +static List *packages_stats = NIL; + +typedef struct tagVariableStatEntry +{ + HTAB *hash; + HASH_SEQ_STATUS *status; + Variable *variable; + Package *package; + int level; +} VariableStatEntry; + +typedef struct tagPackageStatEntry +{ + HASH_SEQ_STATUS *status; + int level; +} PackageStatEntry; + +/* + * Compare functions for VariableStatEntry and PackageStatEntry members. + */ +static bool +VariableStatEntry_status_eq(void *entry, void *value) +{ + return ((VariableStatEntry *) entry)->status == (HASH_SEQ_STATUS *) value; +} + +static bool +VariableStatEntry_variable_eq(void *entry, void *value) +{ + return ((VariableStatEntry *) entry)->variable == (Variable *) value; +} + +static bool +VariableStatEntry_package_eq(void *entry, void *value) +{ + return ((VariableStatEntry *) entry)->package == (Package *) value; +} + +static bool +VariableStatEntry_eq_all(void *entry, void *value) +{ + return true; +} + +static bool +VariableStatEntry_level_eq(void *entry, void *value) +{ + return ((VariableStatEntry *) entry)->level == *(int *) value; +} + +static bool +PackageStatEntry_status_eq(void *entry, void *value) +{ + return ((PackageStatEntry *) entry)->status == (HASH_SEQ_STATUS *) value; +} + +static bool +PackageStatEntry_level_eq(void *entry, void *value) +{ + return ((PackageStatEntry *) entry)->level == *(int *) value; +} + +/* + * VariableStatEntry and PackageStatEntry status member getters. + */ +static HASH_SEQ_STATUS * +VariableStatEntry_status_ptr(void *entry) +{ + return ((VariableStatEntry *) entry)->status; +} + +static HASH_SEQ_STATUS * +PackageStatEntry_status_ptr(void *entry) +{ + return ((PackageStatEntry *) entry)->status; +} + +/* + * Generic remove_if algorithm. + * + * For every item in the list: + * 1. Comapare item with value by eq function call. + * 2. If eq return true, then step 3, else goto 7. + * 3. Delete item from list. + * 4. If term is true, call hash_seq_term. + * 5. Free memory. + * 6. If match_first if true return. + * 7. Fetch next item. + * + */ +typedef struct tagRemoveIfContext +{ + List **list; /* target list */ + void *value; /* value to compare with */ + bool (*eq)(void *, void *); /* list item eq to value func */ + HASH_SEQ_STATUS * (*getter)(void *); /* status getter */ + bool match_first; /* return on first match */ + bool term; /* hash_seq_term on match */ +} RemoveIfContext; + +static void +list_remove_if(RemoveIfContext ctx) +{ +#if (PG_VERSION_NUM < 130000) + ListCell *cell, *next, *prev = NULL; + void *entry = NULL; + + for (cell = list_head(*ctx.list); cell; cell = next) + { + entry = lfirst(cell); + next = lnext(cell); + + if (ctx.eq(entry, ctx.value)) + { + *ctx.list = list_delete_cell(*ctx.list, cell, prev); + + if (ctx.term) + hash_seq_term(ctx.getter(entry)); + + pfree(ctx.getter(entry)); + pfree(entry); + + if (ctx.match_first) + return; + } + else + { + prev = cell; + } + } +#else + /* + * See https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=1cff1b95ab6ddae32faa3efe0d95a820dbfdc164 + * + * Version >= 13 have different lists interface. + */ + ListCell *cell; + void *entry = NULL; + + foreach(cell, *ctx.list) + { + entry = lfirst(cell); + + if (ctx.eq(entry, ctx.value)) + { + *ctx.list = foreach_delete_current(*ctx.list, cell); + + if (ctx.term) + hash_seq_term(ctx.getter(entry)); + + pfree(ctx.getter(entry)); + pfree(entry); + + if (ctx.match_first) + return; + } + } +#endif +} + +/* + * Remove first entry for status. + */ +static void +remove_variables_status(List **list, HASH_SEQ_STATUS *status) +{ + RemoveIfContext ctx = + { + .list = list, + .value = status, + .eq = VariableStatEntry_status_eq, + .getter = VariableStatEntry_status_ptr, + .match_first = true, + .term = false + }; + list_remove_if(ctx); +} + +/* + * Remove first entry for variable. + */ +static void +remove_variables_variable(List **list, Variable *variable) +{ + /* + * It may be more than one item in the list for each variable in case of + * cursor. So match_first is false here. + */ + RemoveIfContext ctx = + { + .list = list, + .value = variable, + .eq = VariableStatEntry_variable_eq, + .getter = VariableStatEntry_status_ptr, + .match_first = false, + .term = true + }; + list_remove_if(ctx); +} + +/* + * Remove all the entries for package. + */ +static void +remove_variables_package(List **list, Package *package) +{ + RemoveIfContext ctx = + { + .list = list, + .value = package, + .eq = VariableStatEntry_package_eq, + .getter = VariableStatEntry_status_ptr, + .match_first = false, + .term = true + }; + list_remove_if(ctx); +} + +/* + * Remove all the entries for level. + */ +static void +remove_variables_level(List **list, int level) +{ + RemoveIfContext ctx = + { + .list = list, + .value = &level, + .eq = VariableStatEntry_level_eq, + .getter = VariableStatEntry_status_ptr, + .match_first = false, + .term = false + }; + list_remove_if(ctx); +} + +/* + * Delete variables stats list. + */ +static void +remove_variables_all(List **list) +{ + RemoveIfContext ctx = + { + .list = list, + .value = NULL, + .eq = VariableStatEntry_eq_all, + .getter = VariableStatEntry_status_ptr, + .match_first = false, + .term = true + }; + list_remove_if(ctx); +} + +/* + * Remove first entrie with status for packages list. + */ +static void +remove_packages_status(List **list, HASH_SEQ_STATUS *status) +{ + RemoveIfContext ctx = + { + .list = list, + .value = status, + .eq = PackageStatEntry_status_eq, + .getter = PackageStatEntry_status_ptr, + .match_first = true, + .term = false + }; + list_remove_if(ctx); +} + +/* + * Remove all the entries with level for packages list. + */ +static void +remove_packages_level(List **list, int level) +{ + RemoveIfContext ctx = + { + .list = list, + .value = &level, + .eq = PackageStatEntry_level_eq, + .getter = PackageStatEntry_status_ptr, + .match_first = false, + .term = true + }; + list_remove_if(ctx); +} + +static void freeStatsLists(void); /* Returns a lists of packages and variables changed at current subxact level */ #define get_actual_changes_list() \ ( \ @@ -595,30 +904,31 @@ variable_select(PG_FUNCTION_ARGS) FuncCallContext *funcctx; HASH_SEQ_STATUS *rstat; HashRecordEntry *item; + text *package_name; + text *var_name; + Package *package; + Variable *variable; - if (SRF_IS_FIRSTCALL()) - { - text *package_name; - text *var_name; - Package *package; - Variable *variable; - MemoryContext oldcontext; - RecordVar *record; + CHECK_ARGS_FOR_NULL(); - CHECK_ARGS_FOR_NULL(); + /* Get arguments */ + package_name = PG_GETARG_TEXT_PP(0); + var_name = PG_GETARG_TEXT_PP(1); - /* Get arguments */ - package_name = PG_GETARG_TEXT_PP(0); - var_name = PG_GETARG_TEXT_PP(1); + package = getPackage(package_name, true); + variable = getVariableInternal(package, var_name, RECORDOID, true, + true); - package = getPackage(package_name, true); - variable = getVariableInternal(package, var_name, RECORDOID, true, - true); + if (SRF_IS_FIRSTCALL()) + { + MemoryContext oldcontext; + RecordVar *record; + VariableStatEntry *entry; record = &(GetActualValue(variable).record); - funcctx = SRF_FIRSTCALL_INIT(); - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + oldcontext = MemoryContextSwitchTo(TopTransactionContext); funcctx->tuple_desc = record->tupdesc; @@ -626,6 +936,14 @@ variable_select(PG_FUNCTION_ARGS) hash_seq_init(rstat, record->rhash); funcctx->user_fctx = rstat; + entry = palloc0(sizeof(VariableStatEntry)); + entry->hash = record->rhash; + entry->status = rstat; + entry->variable = variable; + entry->package = package; + entry->level = GetCurrentTransactionNestLevel(); + variables_stats = lcons((void *)entry, variables_stats); + MemoryContextSwitchTo(oldcontext); PG_FREE_IF_COPY(package_name, 0); PG_FREE_IF_COPY(var_name, 1); @@ -645,7 +963,7 @@ variable_select(PG_FUNCTION_ARGS) } else { - pfree(rstat); + remove_variables_status(&variables_stats, rstat); SRF_RETURN_DONE(funcctx); } } @@ -947,6 +1265,8 @@ remove_package(PG_FUNCTION_ARGS) resetVariablesCache(); + remove_variables_package(&variables_stats, package); + PG_FREE_IF_COPY(package_name, 0); PG_RETURN_VOID(); } @@ -1042,6 +1362,7 @@ remove_packages(PG_FUNCTION_ARGS) } resetVariablesCache(); + remove_variables_all(&variables_stats); PG_RETURN_VOID(); } @@ -1213,7 +1534,7 @@ get_packages_stats(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; MemoryContext oldcontext; - HASH_SEQ_STATUS *pstat; + HASH_SEQ_STATUS *rstat; Package *package; if (SRF_IS_FIRSTCALL()) @@ -1238,11 +1559,20 @@ get_packages_stats(PG_FUNCTION_ARGS) */ if (packagesHash) { - pstat = (HASH_SEQ_STATUS *) palloc0(sizeof(HASH_SEQ_STATUS)); - /* Get packages list */ - hash_seq_init(pstat, packagesHash); + MemoryContext ctx; + PackageStatEntry *entry; - funcctx->user_fctx = pstat; + ctx = MemoryContextSwitchTo(TopTransactionContext); + rstat = (HASH_SEQ_STATUS *) palloc0(sizeof(HASH_SEQ_STATUS)); + /* Get packages list */ + hash_seq_init(rstat, packagesHash); + + funcctx->user_fctx = rstat; + entry = palloc0(sizeof(PackageStatEntry)); + entry->status = rstat; + entry->level = GetCurrentTransactionNestLevel(); + packages_stats = lcons((void *)entry, packages_stats); + MemoryContextSwitchTo(ctx); } else funcctx->user_fctx = NULL; @@ -1255,9 +1585,9 @@ get_packages_stats(PG_FUNCTION_ARGS) SRF_RETURN_DONE(funcctx); /* Get packages list */ - pstat = (HASH_SEQ_STATUS *) funcctx->user_fctx; + rstat = (HASH_SEQ_STATUS *) funcctx->user_fctx; - package = (Package *) hash_seq_search(pstat); + package = (Package *) hash_seq_search(rstat); if (package != NULL) { Datum values[2]; @@ -1289,7 +1619,7 @@ get_packages_stats(PG_FUNCTION_ARGS) } else { - pfree(pstat); + remove_packages_status(&packages_stats, rstat); SRF_RETURN_DONE(funcctx); } } @@ -1749,6 +2079,7 @@ removeObject(TransObject *object, TransObjectType type) /* Remove object from hash table */ hash_search(hash, object->name, HASH_REMOVE, &found); + remove_variables_variable(&variables_stats, (Variable *) object); /* Remove package if it became empty */ if (type == TRANS_VARIABLE && isPackageEmpty(package)) @@ -2131,16 +2462,60 @@ processChanges(Action action) } } +/* + * ATX and connection pooling are not compatible with pg_variables. + */ static void compatibility_check(void) { + /* + * | Edition | ConnPool | ATX | COMPAT_CHECK | + * ------------------------------------------- + * | std 9.6 | no | no | no | + * | std 10 | no | no | yes | + * | std 11 | no | no | yes | + * | std 12 | no | no | yes | + * | std 13 | no | no | yes | + * | ee 9.6 | no | yes | no | + * | ee 10 | no | yes | yes | + * | ee 11 | yes | yes | yes | + * | ee 12 | yes | yes | yes | + * | ee 13 | yes | yes | yes | + */ #ifdef PGPRO_EE -# if (PG_VERSION_NUM < 130000) || \ - ((PG_VERSION_NUM >= 130000) && (defined PGPRO_FEATURE_ATX)) + +# if (PG_VERSION_NUM < 100000) + /* + * This versions does not have dedicated macro to check compatibility. + * So, use simple check here for ATX. + */ if (getNestLevelATX() != 0) - elog(ERROR, "pg_variable extension is not compatible with autonomous transactions and connection pooling"); -# endif -#endif + { + freeStatsLists(); + elog(ERROR, "pg_variables extension is not compatible with " + "autonomous transactions"); + } +# else + /* + * Since ee10 there is PG_COMPATIBILITY_CHECK macro to check compatibility. + * But for some reasons it may not be present at the moment. + * So, if PG_COMPATIBILITY_CHECK macro is not present pg_variables are + * always compatible. + */ +# ifdef PG_COMPATIBILITY_CHECK + { + if (!pg_compatibility_check_no_error()) + freeStatsLists(); + + PG_COMPATIBILITY_CHECK("pg_variables"); + } +# endif /* PG_COMPATIBILITY_CHECK */ +# endif /* PG_VERSION_NUM */ + +# undef ATX_CHECK +# undef CONNPOOL_CHECK + +#endif /* PGPRO_EE */ } /* @@ -2168,6 +2543,9 @@ pgvSubTransCallback(SubXactEvent event, SubTransactionId mySubid, break; } } + + remove_variables_level(&variables_stats, GetCurrentTransactionNestLevel()); + remove_packages_level(&packages_stats, GetCurrentTransactionNestLevel()); } /* @@ -2197,6 +2575,9 @@ pgvTransCallback(XactEvent event, void *arg) break; } } + + if (event == XACT_EVENT_PRE_COMMIT || event == XACT_EVENT_ABORT) + freeStatsLists(); } /* @@ -2209,6 +2590,33 @@ variable_ExecutorEnd(QueryDesc *queryDesc) prev_ExecutorEnd(queryDesc); else standard_ExecutorEnd(queryDesc); + + freeStatsLists(); +} + +/* + * Free hash_seq_search scans + */ +static void +freeStatsLists(void) +{ + ListCell *cell; + + foreach(cell, variables_stats) + { + VariableStatEntry *entry = (VariableStatEntry *) lfirst(cell); + hash_seq_term(entry->status); + } + + variables_stats = NIL; + + foreach(cell, packages_stats) + { + PackageStatEntry *entry = (PackageStatEntry *) lfirst(cell); + hash_seq_term(entry->status); + } + + packages_stats = NIL; } /* diff --git a/sql/pg_variables_trans.sql b/sql/pg_variables_trans.sql index c4b8c90..8cb1d2f 100644 --- a/sql/pg_variables_trans.sql +++ b/sql/pg_variables_trans.sql @@ -614,3 +614,522 @@ SELECT * FROM pgv_list() order by package, name; SELECT pgv_select('test', 'z'); SELECT pgv_free(); + +-- Variables should be rollbackable if transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); +SELECT pgv_select('test', 'x'); + +BEGIN; +SELECT pgv_remove('test', 'x'); +ROLLBACK; + +SELECT pgv_select('test', 'x'); + +BEGIN; +SELECT pgv_remove('test'); +ROLLBACK; + +SELECT pgv_select('test', 'x'); + +BEGIN; +SELECT pgv_free(); +ROLLBACK; + +SELECT pgv_select('test', 'x'); + +--- +--- Variables should not be rollbackable if not transactional +--- +-- case 1 (remove var) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); +SELECT pgv_select('test', 'y'); + +BEGIN; +SELECT pgv_remove('test', 'y'); +ROLLBACK; + +SELECT pgv_select('test', 'y'); +-- case 2 (remove pack) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); +SELECT pgv_select('test', 'y'); + +BEGIN; +SELECT pgv_remove('test'); +ROLLBACK; + +SELECT pgv_select('test', 'y'); +-- case 3 (free) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); +SELECT pgv_select('test', 'y'); + +BEGIN; +SELECT pgv_free(); +ROLLBACK; + +SELECT pgv_select('test', 'y'); +-- clear all +SELECT pgv_free(); + +--- +--- Cursors test #1 (remove var) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'y'); + +SELECT pgv_free(); +--- +--- Cursors test #2 (remove pack) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test'); + +SELECT pgv_free(); +--- +--- Cursors test #3 (free) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test'); + +SELECT pgv_free(); +--- +--- Cursor test #4 +--- + +-- non transactional, remove var +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +-- non transactional, remove pac +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +-- non transactional, free +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +-- transactional, remove var +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'y'); + +-- transactional, remove pack +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'y'); + +-- transactional, free +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'y'); + +SELECT pgv_free(); +--- +--- Cursor test #5 +--- + +-- non transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +CLOSE r1_cur; +SELECT pgv_remove('test', 'x'); +ROLLBACK; +SELECT pgv_select('test', 'x'); + +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +CLOSE r1_cur; +SELECT pgv_remove('test'); +ROLLBACK; +SELECT pgv_select('test', 'x'); + +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +CLOSE r1_cur; +SELECT pgv_free(); +ROLLBACK; +SELECT pgv_select('test', 'x'); + +-- transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test', 'x'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +SELECT pgv_free(); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'x'); + +--- +--- Cursor test #6 +--- +--SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +--BEGIN; +--DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +--FETCH 1 in r1_cur; +--CLOSE r1_cur; +--SELECT pgv_remove('test', 'x'); +--COMMIT; +SELECT pgv_free(); +--- +--- Tests for "leaked hash_seq_search scan for hash table" +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); +SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); +SELECT pgv_select('test', 'x') LIMIT 1; +SELECT pgv_select('test', 'x') LIMIT 2; +SELECT pgv_select('test', 'x') LIMIT 3; +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; +SELECT pgv_select('test', 'x') LIMIT 2; +SELECT pgv_select('test', 'x') LIMIT 3; +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; +SELECT pgv_select('test', 'x') LIMIT 2; +SELECT pgv_select('test', 'x') LIMIT 3; +COMMIT; + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); +SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); +SELECT pgv_select('test', 'y') LIMIT 1; +SELECT pgv_select('test', 'y') LIMIT 2; +SELECT pgv_select('test', 'y') LIMIT 3; +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; +SELECT pgv_select('test', 'y') LIMIT 2; +SELECT pgv_select('test', 'y') LIMIT 3; +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; +SELECT pgv_select('test', 'y') LIMIT 2; +SELECT pgv_select('test', 'y') LIMIT 3; +COMMIT; + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +FETCH 1 in r3_cur; +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; +FETCH 2 in r2_cur; +FETCH 2 in r3_cur; +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; +FETCH 3 in r2_cur; +FETCH 3 in r3_cur; +ROLLBACK; + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +FETCH 1 in r3_cur; +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; +FETCH 2 in r2_cur; +FETCH 2 in r3_cur; +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; +FETCH 3 in r2_cur; +FETCH 3 in r3_cur; +COMMIT; + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +FETCH 2 in r2_cur; +FETCH 3 in r3_cur; +ROLLBACK; + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; +FETCH 2 in r2_cur; +FETCH 3 in r3_cur; +COMMIT; + +--- +--- Some special cases +--- +-- take #1 +SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); +FETCH 1 in r1_cur; +SELECT pgv_remove('test', 'z1'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'z1'); +-- take #2 +SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); +FETCH 1 in r1_cur; +CLOSE r1_cur; +SELECT pgv_remove('test', 'z2'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'z2'); +SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); +-- take #3 +SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +FETCH 1 in r1_cur; +CLOSE r1_cur; +SELECT pgv_remove('test', 'z3'); +FETCH 1 in r1_cur; +ROLLBACK; +SELECT pgv_select('test', 'z3'); + +--BEGIN; +--DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +--FETCH 1 in r1_cur; +--SELECT pgv_remove('test', 'z3'); +--COMMIT; +--SELECT pgv_select('test', 'z3'); + +SELECT pgv_free(); +-- take #4 +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 1 in r1_cur; +ROLLBACK TO SAVEPOINT sp1; +COMMIT; + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 2 in r1_cur; +ROLLBACK TO SAVEPOINT sp1; +COMMIT; + +BEGIN; +SAVEPOINT sp1; +SELECT pgv_select('test', 'x') LIMIT 1; +ROLLBACK TO SAVEPOINT sp1; +COMMIT; + +--- +--- Test cases for pgv_stats +--- +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +COMMIT; + +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +ROLLBACK; + +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); + +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +COMMIT; + +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +ROLLBACK; + +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); + +SELECT pgv_free(); + +--- +--- Some special cases +--- +-- 1 +BEGIN; +SAVEPOINT comm2; +SELECT pgv_insert('test', 'x1', ROW (2::float, 1::float), TRUE); +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +COMMIT; + +-- 2 +BEGIN; +SELECT pgv_insert('test', 'x2', ROW (2::float, 1::float), TRUE); +SAVEPOINT comm2; +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +COMMIT; + +-- 3 +BEGIN; +SELECT pgv_insert('test', 'x3', ROW (2::float, 1::float), TRUE); +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +SAVEPOINT comm2; +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +COMMIT; + +-- 4 +BEGIN; +SELECT pgv_insert('test', 'x4', ROW (2::float, 1::float), TRUE); +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +SAVEPOINT comm2; +FETCH 1 in r2_cur; +COMMIT; + +-- 5 +BEGIN; +SELECT pgv_insert('test', 'x5', ROW (2::float, 1::float), TRUE); +DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +FETCH 1 in r1_cur; +FETCH 1 in r2_cur; +SAVEPOINT comm2; +COMMIT; + +SELECT pgv_free(); From 33a29a046bab830c0117745505629fe4c8a437df Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Mon, 16 Nov 2020 11:31:12 +0300 Subject: [PATCH 09/46] Revert "Merge branch 'master' into stable" This reverts commit 19e5a77db4fc4fe308e3dc0fef559679e809a47e, reversing changes made to 5af86290a8afae3cf1fbbb7a86ac8d4a5bc3b9e9. --- .travis.yml | 13 +- Dockerfile.tmpl | 2 +- expected/pg_variables_trans.out | 1286 ---------- expected/pg_variables_trans_1.out | 3655 ----------------------------- pg_variables.c | 262 +-- sql/pg_variables_trans.sql | 461 ---- 6 files changed, 29 insertions(+), 5650 deletions(-) delete mode 100644 expected/pg_variables_trans_1.out diff --git a/.travis.yml b/.travis.yml index 5882736..7edda6c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +sudo: required + language: c services: @@ -16,22 +18,13 @@ notifications: on_failure: always env: - - PG_VERSION=13 LEVEL=nightmare - - PG_VERSION=13 LEVEL=hardcore - - PG_VERSION=13 - # - PG_VERSION=12 LEVEL=nightmare - - PG_VERSION=12 LEVEL=hardcore - - PG_VERSION=12 - # - PG_VERSION=11 LEVEL=nightmare + - PG_VERSION=11 LEVEL=nightmare - PG_VERSION=11 LEVEL=hardcore - PG_VERSION=11 - PG_VERSION=10 - PG_VERSION=9.6 - PG_VERSION=9.5 -# XXX: consider fixing nightmare mode matrix: allow_failures: - env: PG_VERSION=11 LEVEL=nightmare - - env: PG_VERSION=12 LEVEL=nightmare - - env: PG_VERSION=13 LEVEL=nightmare diff --git a/Dockerfile.tmpl b/Dockerfile.tmpl index 0bcd176..1760377 100644 --- a/Dockerfile.tmpl +++ b/Dockerfile.tmpl @@ -5,7 +5,7 @@ RUN apk add --no-cache \ openssl curl \ perl perl-ipc-run \ make musl-dev gcc bison flex coreutils \ - zlib-dev libedit-dev linux-headers \ + zlib-dev libedit-dev \ clang clang-analyzer; # Install fresh valgrind diff --git a/expected/pg_variables_trans.out b/expected/pg_variables_trans.out index 2ce8138..d73ef69 100644 --- a/expected/pg_variables_trans.out +++ b/expected/pg_variables_trans.out @@ -2367,1289 +2367,3 @@ SELECT pgv_free(); (1 row) --- Variables should be rollbackable if transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - ---- ---- Variables should not be rollbackable if not transactional ---- --- case 1 (remove var) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- case 2 (remove pack) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- case 3 (free) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- clear all -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #1 (remove var) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "y" -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #2 (remove pack) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test'); -ERROR: function pgv_select(unknown) does not exist -LINE 1: SELECT pgv_select('test'); - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #3 (free) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test'); -ERROR: function pgv_select(unknown) does not exist -LINE 1: SELECT pgv_select('test'); - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursor test #4 ---- --- non transactional, remove var -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- non transactional, remove pac -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- non transactional, free -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- transactional, remove var -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - --- transactional, remove pack -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - --- transactional, free -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursor test #5 ---- --- non transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - ---- ---- Cursor test #6 ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -COMMIT; ---- ---- Tests for "leaked hash_seq_search scan for hash table" ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -BEGIN; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -BEGIN; -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r2_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r3_cur; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 3 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r2_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r3_cur; - pgv_select ------------- - (1,2) -(1 row) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 3 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; ---- ---- Some special cases ---- --- take #1 -SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); -FETCH 1 in r1_cur; - pgv_select ------------- - (2,2) -(1 row) - -SELECT pgv_remove('test', 'z1'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "z1" -ROLLBACK; -SELECT pgv_select('test', 'z1'); - pgv_select ------------- - (2,2) -(1 row) - --- take #2 -SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); -FETCH 1 in r1_cur; - pgv_select ------------- - (2,2) -(1 row) - -SELECT pgv_remove('test', 'z2'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "z2" -ROLLBACK; -SELECT pgv_select('test', 'z2'); -ERROR: unrecognized variable "z2" -SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - --- take #3 -SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'z3'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "z3" -ROLLBACK; -SELECT pgv_select('test', 'z3'); - pgv_select ------------- - (1,2) -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'z3'); - pgv_remove ------------- - -(1 row) - -COMMIT; -SELECT pgv_select('test', 'z3'); -ERROR: unrecognized variable "z3" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- take #4 -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SAVEPOINT sp1; -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SAVEPOINT sp1; -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; -BEGIN; -SAVEPOINT sp1; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; ---- ---- Test cases for pgv_stats ---- -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -COMMIT; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); -ERROR: there is a record in the variable "y" with same key -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -ROLLBACK; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); -ERROR: variable "x" already created as TRANSACTIONAL -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -COMMIT; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -ROLLBACK; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - diff --git a/expected/pg_variables_trans_1.out b/expected/pg_variables_trans_1.out deleted file mode 100644 index bc55b84..0000000 --- a/expected/pg_variables_trans_1.out +++ /dev/null @@ -1,3655 +0,0 @@ -SET timezone = 'Europe/Moscow'; -- Need to proper output of datetime variables ---CHECK SAVEPOINT RELEASE -BEGIN; --- Declare variables -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'some value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set_int('vars', 'int1', 101, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'int2', 102); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'intNULL', NULL, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str1', 's101', true); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str2', 's102'); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_numeric('vars', 'num1', 1.01, true); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_numeric('vars', 'num2', 1.02); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd2', '2016-03-30'); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); - pgv_set_jsonb ---------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); - pgv_set_jsonb ---------------- - -(1 row) - -SAVEPOINT comm; --- Set new values -SELECT pgv_set('vars', 'any1', 'another value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'another value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set_int('vars', 'int1', 103, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'int2', 103); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'intNULL', 104, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str1', 's103', true); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str2', 's103'); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_numeric('vars', 'num1', 1.03, true); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_numeric('vars', 'num2', 1.03); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 12:00:00', true); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 12:00:00'); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 12:00:00 GMT+03', true); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 12:00:00 GMT+03'); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd1', '2016-04-02', true); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd2', '2016-04-02'); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j1', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}', true); - pgv_set_jsonb ---------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j2', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'); - pgv_set_jsonb ---------------- - -(1 row) - --- Check values before releasing savepoint -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - 104 -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - --- Check values after releasing savepoint -RELEASE comm; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - 104 -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -COMMIT; -CREATE TABLE tab (id int, t varchar); -INSERT INTO tab VALUES (0, 'str00'), (1, 'str33'), (2, NULL), (NULL, 'strNULL'); -BEGIN; -SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -SELECT pgv_insert('vars3', 'r2', tab) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -SAVEPOINT comm; -SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -RELEASE comm; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -COMMIT; ---CHECK SAVEPOINT ROLLBACK -BEGIN; --- Variables are already declared -SAVEPOINT comm2; --- Set new values -SELECT pgv_set('vars', 'any1', 'one more value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'one more value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set_int('vars', 'int1', 101, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'int2', 102); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'intNULL', NULL, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str1', 's101', true); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str2', 's102'); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_numeric('vars', 'num1', 1.01, true); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_numeric('vars', 'num2', 1.02); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd2', '2016-03-30'); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); - pgv_set_jsonb ---------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); - pgv_set_jsonb ---------------- - -(1 row) - --- Check values before rollback to savepoint -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 101 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 102 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s101 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s102 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.01 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.02 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 10:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 11:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 14:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 16:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 03-29-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 03-30-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ---------------------- - [1, 2, "foo", null] -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb --------------------------------------------------- - {"bar": "baz", "active": false, "balance": 7.77} -(1 row) - --- Check values after rollback to savepoint -ROLLBACK TO comm2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 102 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - 104 -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s102 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.02 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 11:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 16:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 03-30-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb --------------------------------------------------- - {"bar": "baz", "active": false, "balance": 7.77} -(1 row) - -COMMIT; --- Record variables -BEGIN; -SAVEPOINT comm2; -SELECT pgv_delete('vars3', 'r1', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_delete('vars3', 'r2', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -ROLLBACK to comm2; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -COMMIT; --- TRYING TO CHANGE FLAG 'IS_TRANSACTIONAL' -SELECT pgv_set('vars', 'any1', 'value'::text); -ERROR: variable "any1" already created as TRANSACTIONAL -SELECT pgv_set('vars', 'any2', 'value'::text, true); -ERROR: variable "any2" already created as NOT TRANSACTIONAL -SELECT pgv_set_int('vars', 'int1', 301); -ERROR: variable "int1" already created as TRANSACTIONAL -SELECT pgv_set_int('vars', 'int2', 302, true); -ERROR: variable "int2" already created as NOT TRANSACTIONAL -SELECT pgv_set_text('vars', 'str1', 's301'); -ERROR: variable "str1" already created as TRANSACTIONAL -SELECT pgv_set_text('vars', 'str2', 's302', true); -ERROR: variable "str2" already created as NOT TRANSACTIONAL -SELECT pgv_set_numeric('vars', 'num1', 3.01); -ERROR: variable "num1" already created as TRANSACTIONAL -SELECT pgv_set_numeric('vars', 'num2', 3.02, true); -ERROR: variable "num2" already created as NOT TRANSACTIONAL -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 20:00:00'); -ERROR: variable "ts1" already created as TRANSACTIONAL -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 21:00:00', true); -ERROR: variable "ts2" already created as NOT TRANSACTIONAL -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 20:00:00 GMT+01'); -ERROR: variable "tstz1" already created as TRANSACTIONAL -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 21:00:00 GMT+02', true); -ERROR: variable "tstz2" already created as NOT TRANSACTIONAL -SELECT pgv_set_date('vars', 'd1', '2016-04-29'); -ERROR: variable "d1" already created as TRANSACTIONAL -SELECT pgv_set_date('vars', 'd2', '2016-04-30', true); -ERROR: variable "d2" already created as NOT TRANSACTIONAL -SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo2", null]'); -ERROR: variable "j1" already created as TRANSACTIONAL -SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz2", "balance": 7.77, "active": true}', true); -ERROR: variable "j2" already created as NOT TRANSACTIONAL -SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str66' :: varchar)); -ERROR: variable "r1" already created as TRANSACTIONAL -SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str66' :: varchar),true); -ERROR: variable "r2" already created as NOT TRANSACTIONAL --- CHECK pgv_list() WHILE WE HAVE A LOT OF MISCELLANEOUS VARIABLES -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+---------+------------------ - vars | any1 | t - vars | any2 | f - vars | d1 | t - vars | d2 | f - vars | int1 | t - vars | int2 | f - vars | intNULL | t - vars | num1 | t - vars | num2 | f - vars | str1 | t - vars | str2 | f - vars | ts1 | t - vars | ts2 | f - vars | tstz1 | t - vars | tstz2 | f - vars2 | j1 | t - vars2 | j2 | f - vars3 | r1 | t - vars3 | r2 | f -(19 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- VARIABLES DECLARED IN SUBTRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK TO SAVEPOINT --- For better readability we don't use deprecated api functions in test below -BEGIN; -SAVEPOINT sp_to_rollback; -SELECT pgv_set('vars', 'any1', 'text value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'text value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str44' :: varchar), true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str44' :: varchar)); - pgv_insert ------------- - -(1 row) - -ROLLBACK TO sp_to_rollback; -COMMIT; -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized variable "any1" -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ------------- - text value -(1 row) - -SELECT pgv_select('vars3', 'r1'); -ERROR: unrecognized variable "r1" -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (6,str44) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION -BEGIN; -SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp2; -SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------------- - after savepoint sp2 -(1 row) - -ROLLBACK TO sp1; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------------- - before savepoint sp1 -(1 row) - -COMMIT; -BEGIN; -SAVEPOINT sp1; -SAVEPOINT sp2; -SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars2', 'any1',NULL::text); - pgv_get ------------------ - variable exists -(1 row) - -ROLLBACK TO sp1; -COMMIT; -SELECT pgv_get('vars2', 'any1',NULL::text); -ERROR: unrecognized package "vars2" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---CHECK TRANSACTION COMMIT --- Declare variables -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'some value'::text); - pgv_set ---------- - -(1 row) - -BEGIN; --- Set new values -SELECT pgv_set('vars', 'any1', 'another value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'another value'::text); - pgv_set ---------- - -(1 row) - --- Check values before committing transaction -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - --- Check values after committing transaction -COMMIT; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -SELECT pgv_insert('vars3', 'r2', tab) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -BEGIN; -SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -COMMIT; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - --- CHECK TRANSACTION ROLLBACK --- Variables are already declared -BEGIN; --- Set new values -SELECT pgv_set('vars', 'any1', 'one more value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'one more value'::text); - pgv_set ---------- - -(1 row) - --- Check values before rollback -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - --- Check values after rollback -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - --- Record variables -BEGIN; -SELECT pgv_delete('vars3', 'r1', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_delete('vars3', 'r2', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -ROLLBACK; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- VARIABLES DECLARED IN TRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK -BEGIN; -SELECT pgv_set('vars', 'any1', 'text value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'text value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_insert('vars', 'r1', row(6 :: integer, 'str44' :: varchar), true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars', 'r2', row(6 :: integer, 'str44' :: varchar)); - pgv_insert ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized variable "any1" -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ------------- - text value -(1 row) - -SELECT pgv_select('vars', 'r1'); -ERROR: unrecognized variable "r1" -SELECT pgv_select('vars', 'r2'); - pgv_select ------------- - (6,str44) -(1 row) - -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - --- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION -SELECT pgv_set('vars', 'any1', 'before transaction block'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp2; -SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------------- - after savepoint sp2 -(1 row) - -ROLLBACK TO sp1; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------------- - before savepoint sp1 -(1 row) - -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get --------------------------- - before transaction block -(1 row) - -BEGIN; -SAVEPOINT sp1; -SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp1; -SELECT pgv_get('vars2', 'any1',NULL::text); - pgv_get ------------------ - variable exists -(1 row) - -ROLLBACK; -SELECT pgv_get('vars2', 'any1',NULL::text); -ERROR: unrecognized package "vars2" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- Additional tests -SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -BEGIN; -SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'before savepoint sp1' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_update('vars3', 'r1', row(5 :: integer, 'after savepoint sp1' :: varchar)); - pgv_update ------------- - t -(1 row) - -SAVEPOINT sp2; -SELECT pgv_insert('vars3', 'r1', row(7 :: integer, 'row after sp2 to remove in sp4' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SAVEPOINT sp3; -SAVEPOINT sp4; -SELECT pgv_delete('vars3', 'r1', 7); - pgv_delete ------------- - t -(1 row) - -SAVEPOINT sp5; -SELECT pgv_select('vars3', 'r1'); - pgv_select ---------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) -(5 rows) - -ROLLBACK TO sp5; -SELECT pgv_select('vars3', 'r1'); - pgv_select ---------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) -(5 rows) - -RELEASE sp4; -SELECT pgv_select('vars3', 'r1'); - pgv_select ---------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) -(5 rows) - -ROLLBACK TO sp3; -SELECT pgv_select('vars3', 'r1'); - pgv_select --------------------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) - (7,"row after sp2 to remove in sp4") -(6 rows) - -RELEASE sp2; -SELECT pgv_select('vars3', 'r1'); - pgv_select --------------------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) - (7,"row after sp2 to remove in sp4") -(6 rows) - -ROLLBACK TO sp1; -SELECT pgv_select('vars3', 'r1'); - pgv_select ----------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"before savepoint sp1") - (0,str00) -(5 rows) - -COMMIT; -SELECT pgv_select('vars3', 'r1'); - pgv_select ----------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"before savepoint sp1") - (0,str00) -(5 rows) - -SELECT pgv_set('vars', 'any1', 'outer'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_set('vars', 'any1', 'begin'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_set('vars', 'any1', 'sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp2; -SELECT pgv_set('vars', 'any1', 'sp2'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp3; -SAVEPOINT sp4; -SELECT pgv_set('vars', 'any1', 'sp4'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp5; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp4 -(1 row) - -ROLLBACK TO sp5; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp4 -(1 row) - -RELEASE sp4; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp4 -(1 row) - -ROLLBACK TO sp3; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp2 -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp2 -(1 row) - -ROLLBACK TO sp1; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - begin -(1 row) - -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - outer -(1 row) - -BEGIN; -SELECT pgv_set('vars', 'any1', 'wrong type'::varchar, true); -ERROR: variable "any1" requires "text" value -COMMIT; --- THE REMOVAL OF THE VARIABLE MUST BE CANCELED ON ROLLBACK -SELECT pgv_set('vars', 'any1', 'variable exists'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_remove('vars', 'any1'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - f -(1 row) - -ROLLBACK; -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - t -(1 row) - -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ------------------ - variable exists -(1 row) - -BEGIN; -SELECT pgv_remove('vars', 'any1'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - f -(1 row) - -COMMIT; -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - f -(1 row) - -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized package "vars" -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ - vars3 | r1 | t -(1 row) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ - vars3 | r1 | t -(1 row) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -COMMIT; -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -SELECT pgv_set('vars', 'regular', 'regular variable exists'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'trans1', 'trans1 variable exists'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT pgv_free(); -- Check sequential package removal in one subtransaction - pgv_free ----------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -SELECT pgv_set('vars', 'trans2', 'trans2 variable exists'::text, true); - pgv_set ---------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+--------+------------------ - vars | trans2 | t -(1 row) - -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -ROLLBACK; -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+--------+------------------ - vars | trans1 | t -(1 row) - -BEGIN; -SAVEPOINT sp1; -SAVEPOINT sp2; -SAVEPOINT sp3; -SELECT pgv_set('vars2', 'trans2', 'trans2 variable exists'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp4; -SAVEPOINT sp5; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars - vars2 -(2 rows) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -RELEASE sp5; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars - vars2 -(2 rows) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -RELEASE sp4; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars - vars2 -(2 rows) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -COMMIT; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - -BEGIN; -SELECT pgv_set('vars', 'trans1', 'package created'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -SELECT pgv_set('vars', 'trans1', 'package restored'::text, true); - pgv_set ---------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+--------+------------------ - vars | trans1 | t -(1 row) - -COMMIT; -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - --- REMOVED TRANSACTIONAL VARIABLE SHOULD BE NOT ACCESSIBLE THROUGH LastVariable -SELECT pgv_insert('package', 'errs',row(n), true) -FROM generate_series(1,5) AS gs(n) WHERE 1.0/(n-3)<>0; -ERROR: division by zero -SELECT pgv_insert('package', 'errs',row(1), true); - pgv_insert ------------- - -(1 row) - --- Variable should not exists in case when error occurs during creation -SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); -ERROR: could not identify a hash function for type unknown -SELECT pgv_select('vars4', 'r1', 0); -ERROR: unrecognized package "vars4" --- If variable created and removed in same transaction level, --- it should be totally removed and should not be present --- in changes list and cache. -BEGIN; -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT comm; -SELECT pgv_remove('vars', 'any1'); - pgv_remove ------------- - -(1 row) - -RELEASE comm; -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized package "vars" -COMMIT; --- Tests for PGPRO-2440 -SELECT pgv_insert('vars3', 'r3', row(1 :: integer, NULL::varchar), true); - pgv_insert ------------- - -(1 row) - -BEGIN; -SELECT pgv_insert('vars3', 'r3', row(2 :: integer, NULL::varchar), true); - pgv_insert ------------- - -(1 row) - -SAVEPOINT comm; -SELECT pgv_insert('vars3', 'r3', row(3 :: integer, NULL::varchar), true); - pgv_insert ------------- - -(1 row) - -COMMIT; -SELECT pgv_delete('vars3', 'r3', 3); - pgv_delete ------------- - t -(1 row) - -BEGIN; -SELECT pgv_set('vars1', 't1', ''::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars2', 't2', ''::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SAVEPOINT sp2; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ERROR; -ERROR: syntax error at or near "ERROR" -LINE 1: ERROR; - ^ -COMMIT; -BEGIN; -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SAVEPOINT sp_to_rollback; -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -ROLLBACK TO sp_to_rollback; -COMMIT; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - --- Package should exist after rollback if it contains regular variable -BEGIN; -SELECT pgv_set('vars', 'any1', 'some value'::text); - pgv_set ---------- - -(1 row) - -ROLLBACK; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars -(1 row) - --- Package should not exist if it becomes empty in rolled back transaction -BEGIN; -SAVEPOINT comm2; -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -ROLLBACK TO comm2; -SELECT pgv_exists('vars'); - pgv_exists ------------- - f -(1 row) - -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars -(1 row) - -COMMIT; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - -SELECT pgv_set('vars', 'any1', 'some value'::text); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- Variables should be insertable after pgv_remove (variable) -BEGIN; -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -ROLLBACK; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -BEGIN; -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -COMMIT; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | x | t -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - --- Variables should be insertable after pgv_remove (package) -BEGIN; -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -ROLLBACK; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | x | t -(1 row) - -BEGIN; -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -COMMIT; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | y | t -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - --- Variables should be insertable after pgv_free -BEGIN; -SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -ROLLBACK; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | y | t -(1 row) - -BEGIN; -SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -COMMIT; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | z | t -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- Variables should be rollbackable if transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - ---- ---- Variables should not be rollbackable if not transactional ---- --- case 1 (remove var) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- case 2 (remove pack) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- case 3 (free) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- clear all -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #1 (remove var) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "y" -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #2 (remove pack) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test'); -ERROR: function pgv_select(unknown) does not exist -LINE 1: SELECT pgv_select('test'); - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #3 (free) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test'); -ERROR: function pgv_select(unknown) does not exist -LINE 1: SELECT pgv_select('test'); - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursor test #4 ---- --- non transactional, remove var -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- non transactional, remove pac -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- non transactional, free -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- transactional, remove var -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - --- transactional, remove pack -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - --- transactional, free -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursor test #5 ---- --- non transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - ---- ---- Cursor test #6 ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -COMMIT; ---- ---- Tests for "leaked hash_seq_search scan for hash table" ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -BEGIN; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -BEGIN; -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r2_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r3_cur; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 3 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r2_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r3_cur; - pgv_select ------------- - (1,2) -(1 row) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 3 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; ---- ---- Some special cases ---- --- take #1 -SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); -FETCH 1 in r1_cur; - pgv_select ------------- - (2,2) -(1 row) - -SELECT pgv_remove('test', 'z1'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "z1" -ROLLBACK; -SELECT pgv_select('test', 'z1'); - pgv_select ------------- - (2,2) -(1 row) - --- take #2 -SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); -FETCH 1 in r1_cur; - pgv_select ------------- - (2,2) -(1 row) - -SELECT pgv_remove('test', 'z2'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "z2" -ROLLBACK; -SELECT pgv_select('test', 'z2'); -ERROR: unrecognized variable "z2" -SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - --- take #3 -SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'z3'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "z3" -ROLLBACK; -SELECT pgv_select('test', 'z3'); - pgv_select ------------- - (1,2) -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'z3'); - pgv_remove ------------- - -(1 row) - -COMMIT; -SELECT pgv_select('test', 'z3'); -ERROR: unrecognized variable "z3" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- take #4 -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SAVEPOINT sp1; -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SAVEPOINT sp1; -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; -BEGIN; -SAVEPOINT sp1; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; ---- ---- Test cases for pgv_stats ---- -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -COMMIT; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); -ERROR: there is a record in the variable "y" with same key -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -ROLLBACK; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); -ERROR: variable "x" already created as TRANSACTIONAL -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -COMMIT; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -ROLLBACK; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - diff --git a/pg_variables.c b/pg_variables.c index 9e83352..ee1fa3d 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -129,165 +129,6 @@ static ExecutorEnd_hook_type prev_ExecutorEnd = NULL; static dlist_head *changesStack = NULL; static MemoryContext changesStackContext = NULL; -/* - * List to store all the running hash_seq_search, variable and package scan for - * hash table. - * - * NOTE: In function variable_select we use hash_seq_search to find next tuple. - * So, in case user do not get all the data from set at once (use cursors or - * LIMIT) we have to call hash_seq_term to not to leak hash_seq_search scans. - * - * For doing this, we alloc all of the rstats in the TopTransactionContext and - * save pointers to the rstats into list. Once transaction ended (commited or - * aborted) we clear all the "active" hash_seq_search by calling hash_seq_term. - * - * TopTransactionContext is handy here, because it would not be reset by the - * time pgvTransCallback is called. - */ -static List *variables_stats = NIL; -static List *packages_stats = NIL; - -typedef struct tagHtabToStat { - HTAB *hash; - HASH_SEQ_STATUS *status; - Variable *variable; - Package *package; - int level; -} HtabToStat; - -/* - * A bunch of comp functions for HtabToStat members here. - */ -static bool -HtabToStat_status_eq(HtabToStat *entry, void *value) -{ - return entry->status == (HASH_SEQ_STATUS *) value; -} - -static bool -HtabToStat_variable_eq(HtabToStat *entry, void *value) -{ - return entry->variable == (Variable *) value; -} - -static bool -HtabToStat_package_eq(HtabToStat *entry, void *value) -{ - return entry->package == (Package *) value; -} - -static bool -HtabToStat_eq_all(HtabToStat *entry, void *value) -{ - return true; -} - -static bool -HtabToStat_level_eq(HtabToStat *entry, void *value) -{ - return entry->level == *(int *) value; -} - -/* - * Generic remove_if algorithm for HtabToStat. - * - * 'eq' - is a function pointer used to compare list entries to the 'value'. - * 'match_first' - if true return on first match. - */ -static void -HtabToStat_remove_if(List **l, void *value, - bool (*eq)(HtabToStat *, void *), - bool match_first) -{ -#if (PG_VERSION_NUM < 130000) - ListCell *cell, *next, *prev = NULL; - HtabToStat *entry = NULL; - - for (cell = list_head(*l); cell; cell = next) - { - entry = (HtabToStat *) lfirst(cell); - next = lnext(cell); - - if (eq(entry, value)) - { - *l = list_delete_cell(*l, cell, prev); - pfree(entry->status); - pfree(entry); - - if (match_first) - return; - } - else - { - prev = cell; - } - } -#else - /* - * See https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=1cff1b95ab6ddae32faa3efe0d95a820dbfdc164 - * - * Version > 13 have different lists interface. - */ - ListCell *cell; - HtabToStat *entry = NULL; - - foreach(cell, *l) - { - entry = (HtabToStat *) lfirst(cell); - - if (eq(entry, value)) - *l = foreach_delete_current(*l, cell); - } -#endif -} - -/* - * Remove first entry for status. - */ -static void -remove_variables_status(List **l, HASH_SEQ_STATUS *status) -{ - HtabToStat_remove_if(l, status, HtabToStat_status_eq, true); -} - -/* - * Remove first entry for variable. - */ -static void -remove_variables_variable(List **l, Variable *variable) -{ - HtabToStat_remove_if(l, variable, HtabToStat_variable_eq, true); -} - -/* - * Remove all the entries for package. - */ -static void -remove_variables_package(List **l, Package *package) -{ - HtabToStat_remove_if(l, package, HtabToStat_package_eq, false); -} - -/* - * Remove all the entries for level. - */ -static void -remove_variables_level(List **l, int level) -{ - HtabToStat_remove_if(l, &level, HtabToStat_level_eq, false); -} - -/* - * Remove all. - */ -static void -remove_variables_all(List **l) -{ - HtabToStat_remove_if(l, NULL, HtabToStat_eq_all, false); - *l = NIL; -} - -static void freeStatsLists(void); /* Returns a lists of packages and variables changed at current subxact level */ #define get_actual_changes_list() \ ( \ @@ -754,31 +595,30 @@ variable_select(PG_FUNCTION_ARGS) FuncCallContext *funcctx; HASH_SEQ_STATUS *rstat; HashRecordEntry *item; - text *package_name; - text *var_name; - Package *package; - Variable *variable; - CHECK_ARGS_FOR_NULL(); + if (SRF_IS_FIRSTCALL()) + { + text *package_name; + text *var_name; + Package *package; + Variable *variable; + MemoryContext oldcontext; + RecordVar *record; - /* Get arguments */ - package_name = PG_GETARG_TEXT_PP(0); - var_name = PG_GETARG_TEXT_PP(1); + CHECK_ARGS_FOR_NULL(); - package = getPackage(package_name, true); - variable = getVariableInternal(package, var_name, RECORDOID, true, - true); + /* Get arguments */ + package_name = PG_GETARG_TEXT_PP(0); + var_name = PG_GETARG_TEXT_PP(1); - if (SRF_IS_FIRSTCALL()) - { - MemoryContext oldcontext; - RecordVar *record; - HtabToStat *htab_to_stat; + package = getPackage(package_name, true); + variable = getVariableInternal(package, var_name, RECORDOID, true, + true); record = &(GetActualValue(variable).record); - funcctx = SRF_FIRSTCALL_INIT(); - oldcontext = MemoryContextSwitchTo(TopTransactionContext); + funcctx = SRF_FIRSTCALL_INIT(); + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); funcctx->tuple_desc = record->tupdesc; @@ -786,14 +626,6 @@ variable_select(PG_FUNCTION_ARGS) hash_seq_init(rstat, record->rhash); funcctx->user_fctx = rstat; - htab_to_stat = palloc0(sizeof(HtabToStat)); - htab_to_stat->hash = record->rhash; - htab_to_stat->status = rstat; - htab_to_stat->variable = variable; - htab_to_stat->package = package; - htab_to_stat->level = GetCurrentTransactionNestLevel(); - variables_stats = lcons((void *)htab_to_stat, variables_stats); - MemoryContextSwitchTo(oldcontext); PG_FREE_IF_COPY(package_name, 0); PG_FREE_IF_COPY(var_name, 1); @@ -813,7 +645,7 @@ variable_select(PG_FUNCTION_ARGS) } else { - remove_variables_status(&variables_stats, rstat); + pfree(rstat); SRF_RETURN_DONE(funcctx); } } @@ -1115,8 +947,6 @@ remove_package(PG_FUNCTION_ARGS) resetVariablesCache(); - remove_variables_package(&variables_stats, package); - PG_FREE_IF_COPY(package_name, 0); PG_RETURN_VOID(); } @@ -1212,7 +1042,6 @@ remove_packages(PG_FUNCTION_ARGS) } resetVariablesCache(); - remove_variables_all(&variables_stats); PG_RETURN_VOID(); } @@ -1384,7 +1213,7 @@ get_packages_stats(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; MemoryContext oldcontext; - HASH_SEQ_STATUS *rstat; + HASH_SEQ_STATUS *pstat; Package *package; if (SRF_IS_FIRSTCALL()) @@ -1409,16 +1238,11 @@ get_packages_stats(PG_FUNCTION_ARGS) */ if (packagesHash) { - MemoryContext ctx; - - ctx = MemoryContextSwitchTo(TopTransactionContext); - rstat = (HASH_SEQ_STATUS *) palloc0(sizeof(HASH_SEQ_STATUS)); + pstat = (HASH_SEQ_STATUS *) palloc0(sizeof(HASH_SEQ_STATUS)); /* Get packages list */ - hash_seq_init(rstat, packagesHash); + hash_seq_init(pstat, packagesHash); - funcctx->user_fctx = rstat; - packages_stats = lcons((void *)rstat, packages_stats); - MemoryContextSwitchTo(ctx); + funcctx->user_fctx = pstat; } else funcctx->user_fctx = NULL; @@ -1431,9 +1255,9 @@ get_packages_stats(PG_FUNCTION_ARGS) SRF_RETURN_DONE(funcctx); /* Get packages list */ - rstat = (HASH_SEQ_STATUS *) funcctx->user_fctx; + pstat = (HASH_SEQ_STATUS *) funcctx->user_fctx; - package = (Package *) hash_seq_search(rstat); + package = (Package *) hash_seq_search(pstat); if (package != NULL) { Datum values[2]; @@ -1465,8 +1289,7 @@ get_packages_stats(PG_FUNCTION_ARGS) } else { - packages_stats = list_delete(packages_stats, rstat); - pfree(rstat); + pfree(pstat); SRF_RETURN_DONE(funcctx); } } @@ -1926,7 +1749,6 @@ removeObject(TransObject *object, TransObjectType type) /* Remove object from hash table */ hash_search(hash, object->name, HASH_REMOVE, &found); - remove_variables_variable(&variables_stats, (Variable *) object); /* Remove package if it became empty */ if (type == TRANS_VARIABLE && isPackageEmpty(package)) @@ -2346,8 +2168,6 @@ pgvSubTransCallback(SubXactEvent event, SubTransactionId mySubid, break; } } - - remove_variables_level(&variables_stats, GetCurrentTransactionNestLevel()); } /* @@ -2377,9 +2197,6 @@ pgvTransCallback(XactEvent event, void *arg) break; } } - - if (event == XACT_EVENT_PRE_COMMIT || event == XACT_EVENT_ABORT) - freeStatsLists(); } /* @@ -2392,35 +2209,6 @@ variable_ExecutorEnd(QueryDesc *queryDesc) prev_ExecutorEnd(queryDesc); else standard_ExecutorEnd(queryDesc); - - freeStatsLists(); -} - -/* - * Free hash_seq_search scans - */ -static void -freeStatsLists(void) -{ - ListCell *cell; - HASH_SEQ_STATUS *status; - HtabToStat *htab_to_stat; - - foreach(cell, variables_stats) - { - htab_to_stat = (HtabToStat *) lfirst(cell); - hash_seq_term(htab_to_stat->status); - } - - variables_stats = NIL; - - foreach(cell, packages_stats) - { - status = (HASH_SEQ_STATUS *) lfirst(cell); - hash_seq_term(status); - } - - packages_stats = NIL; } /* diff --git a/sql/pg_variables_trans.sql b/sql/pg_variables_trans.sql index 2b83ab5..c4b8c90 100644 --- a/sql/pg_variables_trans.sql +++ b/sql/pg_variables_trans.sql @@ -614,464 +614,3 @@ SELECT * FROM pgv_list() order by package, name; SELECT pgv_select('test', 'z'); SELECT pgv_free(); - --- Variables should be rollbackable if transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); -SELECT pgv_select('test', 'x'); - -BEGIN; -SELECT pgv_remove('test', 'x'); -ROLLBACK; - -SELECT pgv_select('test', 'x'); - -BEGIN; -SELECT pgv_remove('test'); -ROLLBACK; - -SELECT pgv_select('test', 'x'); - -BEGIN; -SELECT pgv_free(); -ROLLBACK; - -SELECT pgv_select('test', 'x'); - ---- ---- Variables should not be rollbackable if not transactional ---- --- case 1 (remove var) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); -SELECT pgv_select('test', 'y'); - -BEGIN; -SELECT pgv_remove('test', 'y'); -ROLLBACK; - -SELECT pgv_select('test', 'y'); --- case 2 (remove pack) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); -SELECT pgv_select('test', 'y'); - -BEGIN; -SELECT pgv_remove('test'); -ROLLBACK; - -SELECT pgv_select('test', 'y'); --- case 3 (free) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); -SELECT pgv_select('test', 'y'); - -BEGIN; -SELECT pgv_free(); -ROLLBACK; - -SELECT pgv_select('test', 'y'); --- clear all -SELECT pgv_free(); - ---- ---- Cursors test #1 (remove var) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test', 'x'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test', 'y'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'y'); - -SELECT pgv_free(); ---- ---- Cursors test #2 (remove pack) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test'); - -SELECT pgv_free(); ---- ---- Cursors test #3 (free) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_free(); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_free(); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test'); - -SELECT pgv_free(); ---- ---- Cursor test #4 ---- - --- non transactional, remove var -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test', 'x'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - --- non transactional, remove pac -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - --- non transactional, free -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_free(); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - --- transactional, remove var -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test', 'y'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'y'); - --- transactional, remove pack -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'y'); - --- transactional, free -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_free(); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'y'); - -SELECT pgv_free(); ---- ---- Cursor test #5 ---- - --- non transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; -SELECT pgv_remove('test', 'x'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; -SELECT pgv_remove('test'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; -SELECT pgv_free(); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - --- transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; -SELECT pgv_remove('test', 'x'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; -SELECT pgv_remove('test'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; -SELECT pgv_free(); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'x'); - ---- ---- Cursor test #6 ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; -SELECT pgv_remove('test', 'x'); -COMMIT; - ---- ---- Tests for "leaked hash_seq_search scan for hash table" ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); -SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); -SELECT pgv_select('test', 'x') LIMIT 1; -SELECT pgv_select('test', 'x') LIMIT 2; -SELECT pgv_select('test', 'x') LIMIT 3; -BEGIN; -SELECT pgv_select('test', 'x') LIMIT 1; -SELECT pgv_select('test', 'x') LIMIT 2; -SELECT pgv_select('test', 'x') LIMIT 3; -ROLLBACK; -BEGIN; -SELECT pgv_select('test', 'x') LIMIT 1; -SELECT pgv_select('test', 'x') LIMIT 2; -SELECT pgv_select('test', 'x') LIMIT 3; -COMMIT; - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); -SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); -SELECT pgv_select('test', 'y') LIMIT 1; -SELECT pgv_select('test', 'y') LIMIT 2; -SELECT pgv_select('test', 'y') LIMIT 3; -BEGIN; -SELECT pgv_select('test', 'y') LIMIT 1; -SELECT pgv_select('test', 'y') LIMIT 2; -SELECT pgv_select('test', 'y') LIMIT 3; -ROLLBACK; -BEGIN; -SELECT pgv_select('test', 'y') LIMIT 1; -SELECT pgv_select('test', 'y') LIMIT 2; -SELECT pgv_select('test', 'y') LIMIT 3; -COMMIT; - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; -FETCH 1 in r2_cur; -FETCH 1 in r3_cur; -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 2 in r1_cur; -FETCH 2 in r2_cur; -FETCH 2 in r3_cur; -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 3 in r1_cur; -FETCH 3 in r2_cur; -FETCH 3 in r3_cur; -ROLLBACK; - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; -FETCH 1 in r2_cur; -FETCH 1 in r3_cur; -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 2 in r1_cur; -FETCH 2 in r2_cur; -FETCH 2 in r3_cur; -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 3 in r1_cur; -FETCH 3 in r2_cur; -FETCH 3 in r3_cur; -COMMIT; - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; -FETCH 2 in r2_cur; -FETCH 3 in r3_cur; -ROLLBACK; - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; -FETCH 2 in r2_cur; -FETCH 3 in r3_cur; -COMMIT; - ---- ---- Some special cases ---- --- take #1 -SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); -FETCH 1 in r1_cur; -SELECT pgv_remove('test', 'z1'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'z1'); --- take #2 -SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); -FETCH 1 in r1_cur; -SELECT pgv_remove('test', 'z2'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'z2'); -SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); --- take #3 -SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); -FETCH 1 in r1_cur; -SELECT pgv_remove('test', 'z3'); -FETCH 1 in r1_cur; -ROLLBACK; -SELECT pgv_select('test', 'z3'); - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); -FETCH 1 in r1_cur; -SELECT pgv_remove('test', 'z3'); -COMMIT; -SELECT pgv_select('test', 'z3'); - -SELECT pgv_free(); --- take #4 -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SAVEPOINT sp1; -FETCH 1 in r1_cur; -ROLLBACK TO SAVEPOINT sp1; -COMMIT; - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SAVEPOINT sp1; -FETCH 2 in r1_cur; -ROLLBACK TO SAVEPOINT sp1; -COMMIT; - -BEGIN; -SAVEPOINT sp1; -SELECT pgv_select('test', 'x') LIMIT 1; -ROLLBACK TO SAVEPOINT sp1; -COMMIT; - ---- ---- Test cases for pgv_stats ---- -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); -SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; -FETCH 1 in r2_cur; -COMMIT; - -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; -FETCH 1 in r2_cur; -ROLLBACK; - -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); - -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; -FETCH 1 in r2_cur; -COMMIT; - -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; -FETCH 1 in r2_cur; -ROLLBACK; - -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); - -SELECT pgv_free(); From 2c47f47054fc367806c89dce49ecce11ebf574d5 Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Mon, 16 Nov 2020 15:58:28 +0300 Subject: [PATCH 10/46] Revert "Revert "Merge branch 'master' into stable"" This reverts commit 33a29a046bab830c0117745505629fe4c8a437df. --- .travis.yml | 13 ++++++++++--- Dockerfile.tmpl | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7edda6c..5882736 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,3 @@ -sudo: required - language: c services: @@ -18,13 +16,22 @@ notifications: on_failure: always env: - - PG_VERSION=11 LEVEL=nightmare + - PG_VERSION=13 LEVEL=nightmare + - PG_VERSION=13 LEVEL=hardcore + - PG_VERSION=13 + # - PG_VERSION=12 LEVEL=nightmare + - PG_VERSION=12 LEVEL=hardcore + - PG_VERSION=12 + # - PG_VERSION=11 LEVEL=nightmare - PG_VERSION=11 LEVEL=hardcore - PG_VERSION=11 - PG_VERSION=10 - PG_VERSION=9.6 - PG_VERSION=9.5 +# XXX: consider fixing nightmare mode matrix: allow_failures: - env: PG_VERSION=11 LEVEL=nightmare + - env: PG_VERSION=12 LEVEL=nightmare + - env: PG_VERSION=13 LEVEL=nightmare diff --git a/Dockerfile.tmpl b/Dockerfile.tmpl index 1760377..0bcd176 100644 --- a/Dockerfile.tmpl +++ b/Dockerfile.tmpl @@ -5,7 +5,7 @@ RUN apk add --no-cache \ openssl curl \ perl perl-ipc-run \ make musl-dev gcc bison flex coreutils \ - zlib-dev libedit-dev \ + zlib-dev libedit-dev linux-headers \ clang clang-analyzer; # Install fresh valgrind From 8ee0641cfc40deafbb1484fa682718c5b4fb9099 Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Mon, 7 Dec 2020 15:46:42 +0300 Subject: [PATCH 11/46] Issue #33: fix pg_variables_trans test fail on sparc. Add sort order for pgv_stats call. Do not use exact allocated memory size as checked value. Remove multiple output from pg_variables_trans test. --- expected/pg_variables_trans.out | 155 +- expected/pg_variables_trans_1.out | 3764 ----------------------------- expected/pg_variables_trans_2.out | 3764 ----------------------------- sql/pg_variables_trans.sql | 48 +- 4 files changed, 113 insertions(+), 7618 deletions(-) delete mode 100644 expected/pg_variables_trans_1.out delete mode 100644 expected/pg_variables_trans_2.out diff --git a/expected/pg_variables_trans.out b/expected/pg_variables_trans.out index 8113fc8..2389efa 100644 --- a/expected/pg_variables_trans.out +++ b/expected/pg_variables_trans.out @@ -3539,6 +3539,16 @@ COMMIT; --- --- Test cases for pgv_stats --- +--- Amount of allocated memory may vary from version to version, as well as from +--- platform to platform. Moreover, postgres versions less than 90600 always +--- show zero allocated memory. So, it's much easier to check if allocated +--- memory size is multiple of 8k since we use ALLOCSET_DEFAULT_INITSIZE +--- (see memutils.h), insted of creating multiple outputs files. +--- +CREATE TEMP VIEW pgv_stats_view(pack, mem_mult) AS + SELECT package, allocated_memory % 8192 as allocated_multiple_8192 + FROM pgv_stats() + ORDER BY 1; SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); pgv_insert ------------ @@ -3552,36 +3562,36 @@ SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); (1 row) BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) + pack | mem_mult +------+---------- + test | 0 (1 row) FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) + pack | mem_mult +------+---------- + test | 0 (1 row) COMMIT; SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); ERROR: there is a record in the variable "y" with same key BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) + pack | mem_mult +------+---------- + test | 0 (1 row) FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) + pack | mem_mult +------+---------- + test | 0 (1 row) ROLLBACK; @@ -3592,36 +3602,36 @@ ERROR: variable "y" already created as TRANSACTIONAL SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); ERROR: variable "x" already created as TRANSACTIONAL BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) + pack | mem_mult +------+---------- + test | 0 (1 row) FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) + pack | mem_mult +------+---------- + test | 0 (1 row) COMMIT; SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); ERROR: variable "y" already created as TRANSACTIONAL BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) + pack | mem_mult +------+---------- + test | 0 (1 row) FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) + pack | mem_mult +------+---------- + test | 0 (1 row) ROLLBACK; @@ -3645,18 +3655,18 @@ SELECT pgv_insert('test', 'x1', ROW (2::float, 1::float), TRUE); (1 row) -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) + pack | mem_mult +------+---------- + test | 0 (1 row) FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) + pack | mem_mult +------+---------- + test | 0 (1 row) COMMIT; @@ -3669,18 +3679,18 @@ SELECT pgv_insert('test', 'x2', ROW (2::float, 1::float), TRUE); (1 row) SAVEPOINT comm2; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; - pgv_stats --------------- - (test,49152) + pack | mem_mult +------+---------- + test | 0 (1 row) FETCH 1 in r2_cur; - pgv_stats --------------- - (test,49152) + pack | mem_mult +------+---------- + test | 0 (1 row) COMMIT; @@ -3692,19 +3702,19 @@ SELECT pgv_insert('test', 'x3', ROW (2::float, 1::float), TRUE); (1 row) -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; SAVEPOINT comm2; FETCH 1 in r1_cur; - pgv_stats --------------- - (test,65536) + pack | mem_mult +------+---------- + test | 0 (1 row) FETCH 1 in r2_cur; - pgv_stats --------------- - (test,65536) + pack | mem_mult +------+---------- + test | 0 (1 row) COMMIT; @@ -3716,19 +3726,19 @@ SELECT pgv_insert('test', 'x4', ROW (2::float, 1::float), TRUE); (1 row) -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; - pgv_stats --------------- - (test,81920) + pack | mem_mult +------+---------- + test | 0 (1 row) SAVEPOINT comm2; FETCH 1 in r2_cur; - pgv_stats --------------- - (test,81920) + pack | mem_mult +------+---------- + test | 0 (1 row) COMMIT; @@ -3740,22 +3750,23 @@ SELECT pgv_insert('test', 'x5', ROW (2::float, 1::float), TRUE); (1 row) -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; - pgv_stats --------------- - (test,98304) + pack | mem_mult +------+---------- + test | 0 (1 row) FETCH 1 in r2_cur; - pgv_stats --------------- - (test,98304) + pack | mem_mult +------+---------- + test | 0 (1 row) SAVEPOINT comm2; COMMIT; +DROP VIEW pgv_stats_view; SELECT pgv_free(); pgv_free ---------- diff --git a/expected/pg_variables_trans_1.out b/expected/pg_variables_trans_1.out deleted file mode 100644 index b6f8132..0000000 --- a/expected/pg_variables_trans_1.out +++ /dev/null @@ -1,3764 +0,0 @@ -SET timezone = 'Europe/Moscow'; -- Need to proper output of datetime variables ---CHECK SAVEPOINT RELEASE -BEGIN; --- Declare variables -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'some value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set_int('vars', 'int1', 101, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'int2', 102); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'intNULL', NULL, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str1', 's101', true); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str2', 's102'); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_numeric('vars', 'num1', 1.01, true); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_numeric('vars', 'num2', 1.02); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd2', '2016-03-30'); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); - pgv_set_jsonb ---------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); - pgv_set_jsonb ---------------- - -(1 row) - -SAVEPOINT comm; --- Set new values -SELECT pgv_set('vars', 'any1', 'another value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'another value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set_int('vars', 'int1', 103, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'int2', 103); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'intNULL', 104, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str1', 's103', true); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str2', 's103'); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_numeric('vars', 'num1', 1.03, true); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_numeric('vars', 'num2', 1.03); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 12:00:00', true); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 12:00:00'); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 12:00:00 GMT+03', true); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 12:00:00 GMT+03'); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd1', '2016-04-02', true); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd2', '2016-04-02'); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j1', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}', true); - pgv_set_jsonb ---------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j2', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'); - pgv_set_jsonb ---------------- - -(1 row) - --- Check values before releasing savepoint -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - 104 -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - --- Check values after releasing savepoint -RELEASE comm; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - 104 -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -COMMIT; -CREATE TABLE tab (id int, t varchar); -INSERT INTO tab VALUES (0, 'str00'), (1, 'str33'), (2, NULL), (NULL, 'strNULL'); -BEGIN; -SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -SELECT pgv_insert('vars3', 'r2', tab) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -SAVEPOINT comm; -SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -RELEASE comm; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -COMMIT; ---CHECK SAVEPOINT ROLLBACK -BEGIN; --- Variables are already declared -SAVEPOINT comm2; --- Set new values -SELECT pgv_set('vars', 'any1', 'one more value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'one more value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set_int('vars', 'int1', 101, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'int2', 102); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'intNULL', NULL, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str1', 's101', true); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str2', 's102'); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_numeric('vars', 'num1', 1.01, true); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_numeric('vars', 'num2', 1.02); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd2', '2016-03-30'); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); - pgv_set_jsonb ---------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); - pgv_set_jsonb ---------------- - -(1 row) - --- Check values before rollback to savepoint -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 101 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 102 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s101 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s102 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.01 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.02 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 10:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 11:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 14:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 16:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 03-29-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 03-30-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ---------------------- - [1, 2, "foo", null] -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb --------------------------------------------------- - {"bar": "baz", "active": false, "balance": 7.77} -(1 row) - --- Check values after rollback to savepoint -ROLLBACK TO comm2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 102 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - 104 -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s102 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.02 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 11:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 16:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 03-30-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb --------------------------------------------------- - {"bar": "baz", "active": false, "balance": 7.77} -(1 row) - -COMMIT; --- Record variables -BEGIN; -SAVEPOINT comm2; -SELECT pgv_delete('vars3', 'r1', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_delete('vars3', 'r2', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -ROLLBACK to comm2; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -COMMIT; --- TRYING TO CHANGE FLAG 'IS_TRANSACTIONAL' -SELECT pgv_set('vars', 'any1', 'value'::text); -ERROR: variable "any1" already created as TRANSACTIONAL -SELECT pgv_set('vars', 'any2', 'value'::text, true); -ERROR: variable "any2" already created as NOT TRANSACTIONAL -SELECT pgv_set_int('vars', 'int1', 301); -ERROR: variable "int1" already created as TRANSACTIONAL -SELECT pgv_set_int('vars', 'int2', 302, true); -ERROR: variable "int2" already created as NOT TRANSACTIONAL -SELECT pgv_set_text('vars', 'str1', 's301'); -ERROR: variable "str1" already created as TRANSACTIONAL -SELECT pgv_set_text('vars', 'str2', 's302', true); -ERROR: variable "str2" already created as NOT TRANSACTIONAL -SELECT pgv_set_numeric('vars', 'num1', 3.01); -ERROR: variable "num1" already created as TRANSACTIONAL -SELECT pgv_set_numeric('vars', 'num2', 3.02, true); -ERROR: variable "num2" already created as NOT TRANSACTIONAL -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 20:00:00'); -ERROR: variable "ts1" already created as TRANSACTIONAL -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 21:00:00', true); -ERROR: variable "ts2" already created as NOT TRANSACTIONAL -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 20:00:00 GMT+01'); -ERROR: variable "tstz1" already created as TRANSACTIONAL -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 21:00:00 GMT+02', true); -ERROR: variable "tstz2" already created as NOT TRANSACTIONAL -SELECT pgv_set_date('vars', 'd1', '2016-04-29'); -ERROR: variable "d1" already created as TRANSACTIONAL -SELECT pgv_set_date('vars', 'd2', '2016-04-30', true); -ERROR: variable "d2" already created as NOT TRANSACTIONAL -SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo2", null]'); -ERROR: variable "j1" already created as TRANSACTIONAL -SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz2", "balance": 7.77, "active": true}', true); -ERROR: variable "j2" already created as NOT TRANSACTIONAL -SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str66' :: varchar)); -ERROR: variable "r1" already created as TRANSACTIONAL -SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str66' :: varchar),true); -ERROR: variable "r2" already created as NOT TRANSACTIONAL --- CHECK pgv_list() WHILE WE HAVE A LOT OF MISCELLANEOUS VARIABLES -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+---------+------------------ - vars | any1 | t - vars | any2 | f - vars | d1 | t - vars | d2 | f - vars | int1 | t - vars | int2 | f - vars | intNULL | t - vars | num1 | t - vars | num2 | f - vars | str1 | t - vars | str2 | f - vars | ts1 | t - vars | ts2 | f - vars | tstz1 | t - vars | tstz2 | f - vars2 | j1 | t - vars2 | j2 | f - vars3 | r1 | t - vars3 | r2 | f -(19 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- VARIABLES DECLARED IN SUBTRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK TO SAVEPOINT --- For better readability we don't use deprecated api functions in test below -BEGIN; -SAVEPOINT sp_to_rollback; -SELECT pgv_set('vars', 'any1', 'text value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'text value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str44' :: varchar), true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str44' :: varchar)); - pgv_insert ------------- - -(1 row) - -ROLLBACK TO sp_to_rollback; -COMMIT; -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized variable "any1" -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ------------- - text value -(1 row) - -SELECT pgv_select('vars3', 'r1'); -ERROR: unrecognized variable "r1" -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (6,str44) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION -BEGIN; -SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp2; -SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------------- - after savepoint sp2 -(1 row) - -ROLLBACK TO sp1; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------------- - before savepoint sp1 -(1 row) - -COMMIT; -BEGIN; -SAVEPOINT sp1; -SAVEPOINT sp2; -SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars2', 'any1',NULL::text); - pgv_get ------------------ - variable exists -(1 row) - -ROLLBACK TO sp1; -COMMIT; -SELECT pgv_get('vars2', 'any1',NULL::text); -ERROR: unrecognized package "vars2" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---CHECK TRANSACTION COMMIT --- Declare variables -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'some value'::text); - pgv_set ---------- - -(1 row) - -BEGIN; --- Set new values -SELECT pgv_set('vars', 'any1', 'another value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'another value'::text); - pgv_set ---------- - -(1 row) - --- Check values before committing transaction -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - --- Check values after committing transaction -COMMIT; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -SELECT pgv_insert('vars3', 'r2', tab) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -BEGIN; -SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -COMMIT; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - --- CHECK TRANSACTION ROLLBACK --- Variables are already declared -BEGIN; --- Set new values -SELECT pgv_set('vars', 'any1', 'one more value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'one more value'::text); - pgv_set ---------- - -(1 row) - --- Check values before rollback -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - --- Check values after rollback -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - --- Record variables -BEGIN; -SELECT pgv_delete('vars3', 'r1', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_delete('vars3', 'r2', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -ROLLBACK; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- VARIABLES DECLARED IN TRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK -BEGIN; -SELECT pgv_set('vars', 'any1', 'text value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'text value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_insert('vars', 'r1', row(6 :: integer, 'str44' :: varchar), true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars', 'r2', row(6 :: integer, 'str44' :: varchar)); - pgv_insert ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized variable "any1" -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ------------- - text value -(1 row) - -SELECT pgv_select('vars', 'r1'); -ERROR: unrecognized variable "r1" -SELECT pgv_select('vars', 'r2'); - pgv_select ------------- - (6,str44) -(1 row) - -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - --- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION -SELECT pgv_set('vars', 'any1', 'before transaction block'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp2; -SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------------- - after savepoint sp2 -(1 row) - -ROLLBACK TO sp1; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------------- - before savepoint sp1 -(1 row) - -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get --------------------------- - before transaction block -(1 row) - -BEGIN; -SAVEPOINT sp1; -SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp1; -SELECT pgv_get('vars2', 'any1',NULL::text); - pgv_get ------------------ - variable exists -(1 row) - -ROLLBACK; -SELECT pgv_get('vars2', 'any1',NULL::text); -ERROR: unrecognized package "vars2" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- Additional tests -SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -BEGIN; -SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'before savepoint sp1' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_update('vars3', 'r1', row(5 :: integer, 'after savepoint sp1' :: varchar)); - pgv_update ------------- - t -(1 row) - -SAVEPOINT sp2; -SELECT pgv_insert('vars3', 'r1', row(7 :: integer, 'row after sp2 to remove in sp4' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SAVEPOINT sp3; -SAVEPOINT sp4; -SELECT pgv_delete('vars3', 'r1', 7); - pgv_delete ------------- - t -(1 row) - -SAVEPOINT sp5; -SELECT pgv_select('vars3', 'r1'); - pgv_select ---------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) -(5 rows) - -ROLLBACK TO sp5; -SELECT pgv_select('vars3', 'r1'); - pgv_select ---------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) -(5 rows) - -RELEASE sp4; -SELECT pgv_select('vars3', 'r1'); - pgv_select ---------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) -(5 rows) - -ROLLBACK TO sp3; -SELECT pgv_select('vars3', 'r1'); - pgv_select --------------------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) - (7,"row after sp2 to remove in sp4") -(6 rows) - -RELEASE sp2; -SELECT pgv_select('vars3', 'r1'); - pgv_select --------------------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) - (7,"row after sp2 to remove in sp4") -(6 rows) - -ROLLBACK TO sp1; -SELECT pgv_select('vars3', 'r1'); - pgv_select ----------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"before savepoint sp1") - (0,str00) -(5 rows) - -COMMIT; -SELECT pgv_select('vars3', 'r1'); - pgv_select ----------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"before savepoint sp1") - (0,str00) -(5 rows) - -SELECT pgv_set('vars', 'any1', 'outer'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_set('vars', 'any1', 'begin'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_set('vars', 'any1', 'sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp2; -SELECT pgv_set('vars', 'any1', 'sp2'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp3; -SAVEPOINT sp4; -SELECT pgv_set('vars', 'any1', 'sp4'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp5; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp4 -(1 row) - -ROLLBACK TO sp5; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp4 -(1 row) - -RELEASE sp4; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp4 -(1 row) - -ROLLBACK TO sp3; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp2 -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp2 -(1 row) - -ROLLBACK TO sp1; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - begin -(1 row) - -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - outer -(1 row) - -BEGIN; -SELECT pgv_set('vars', 'any1', 'wrong type'::varchar, true); -ERROR: variable "any1" requires "text" value -COMMIT; --- THE REMOVAL OF THE VARIABLE MUST BE CANCELED ON ROLLBACK -SELECT pgv_set('vars', 'any1', 'variable exists'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_remove('vars', 'any1'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - f -(1 row) - -ROLLBACK; -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - t -(1 row) - -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ------------------ - variable exists -(1 row) - -BEGIN; -SELECT pgv_remove('vars', 'any1'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - f -(1 row) - -COMMIT; -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - f -(1 row) - -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized package "vars" -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ - vars3 | r1 | t -(1 row) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ - vars3 | r1 | t -(1 row) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -COMMIT; -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -SELECT pgv_set('vars', 'regular', 'regular variable exists'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'trans1', 'trans1 variable exists'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT pgv_free(); -- Check sequential package removal in one subtransaction - pgv_free ----------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -SELECT pgv_set('vars', 'trans2', 'trans2 variable exists'::text, true); - pgv_set ---------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+--------+------------------ - vars | trans2 | t -(1 row) - -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -ROLLBACK; -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+--------+------------------ - vars | trans1 | t -(1 row) - -BEGIN; -SAVEPOINT sp1; -SAVEPOINT sp2; -SAVEPOINT sp3; -SELECT pgv_set('vars2', 'trans2', 'trans2 variable exists'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp4; -SAVEPOINT sp5; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars - vars2 -(2 rows) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -RELEASE sp5; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars - vars2 -(2 rows) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -RELEASE sp4; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars - vars2 -(2 rows) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -COMMIT; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - -BEGIN; -SELECT pgv_set('vars', 'trans1', 'package created'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -SELECT pgv_set('vars', 'trans1', 'package restored'::text, true); - pgv_set ---------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+--------+------------------ - vars | trans1 | t -(1 row) - -COMMIT; -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - --- REMOVED TRANSACTIONAL VARIABLE SHOULD BE NOT ACCESSIBLE THROUGH LastVariable -SELECT pgv_insert('package', 'errs',row(n), true) -FROM generate_series(1,5) AS gs(n) WHERE 1.0/(n-3)<>0; -ERROR: division by zero -SELECT pgv_insert('package', 'errs',row(1), true); - pgv_insert ------------- - -(1 row) - --- Variable should not exists in case when error occurs during creation -SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); -ERROR: could not identify a hash function for type unknown -SELECT pgv_select('vars4', 'r1', 0); -ERROR: unrecognized package "vars4" --- If variable created and removed in same transaction level, --- it should be totally removed and should not be present --- in changes list and cache. -BEGIN; -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT comm; -SELECT pgv_remove('vars', 'any1'); - pgv_remove ------------- - -(1 row) - -RELEASE comm; -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized package "vars" -COMMIT; --- Tests for PGPRO-2440 -SELECT pgv_insert('vars3', 'r3', row(1 :: integer, NULL::varchar), true); - pgv_insert ------------- - -(1 row) - -BEGIN; -SELECT pgv_insert('vars3', 'r3', row(2 :: integer, NULL::varchar), true); - pgv_insert ------------- - -(1 row) - -SAVEPOINT comm; -SELECT pgv_insert('vars3', 'r3', row(3 :: integer, NULL::varchar), true); - pgv_insert ------------- - -(1 row) - -COMMIT; -SELECT pgv_delete('vars3', 'r3', 3); - pgv_delete ------------- - t -(1 row) - -BEGIN; -SELECT pgv_set('vars1', 't1', ''::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars2', 't2', ''::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SAVEPOINT sp2; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ERROR; -ERROR: syntax error at or near "ERROR" -LINE 1: ERROR; - ^ -COMMIT; -BEGIN; -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SAVEPOINT sp_to_rollback; -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -ROLLBACK TO sp_to_rollback; -COMMIT; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - --- Package should exist after rollback if it contains regular variable -BEGIN; -SELECT pgv_set('vars', 'any1', 'some value'::text); - pgv_set ---------- - -(1 row) - -ROLLBACK; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars -(1 row) - --- Package should not exist if it becomes empty in rolled back transaction -BEGIN; -SAVEPOINT comm2; -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -ROLLBACK TO comm2; -SELECT pgv_exists('vars'); - pgv_exists ------------- - f -(1 row) - -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars -(1 row) - -COMMIT; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - -SELECT pgv_set('vars', 'any1', 'some value'::text); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- Variables should be insertable after pgv_remove (variable) -BEGIN; -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -ROLLBACK; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -BEGIN; -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -COMMIT; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | x | t -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - --- Variables should be insertable after pgv_remove (package) -BEGIN; -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -ROLLBACK; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | x | t -(1 row) - -BEGIN; -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -COMMIT; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | y | t -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - --- Variables should be insertable after pgv_free -BEGIN; -SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -ROLLBACK; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | y | t -(1 row) - -BEGIN; -SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -COMMIT; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | z | t -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- Variables should be rollbackable if transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - ---- ---- Variables should not be rollbackable if not transactional ---- --- case 1 (remove var) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- case 2 (remove pack) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- case 3 (free) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- clear all -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #1 (remove var) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "y" -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #2 (remove pack) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test'); -ERROR: function pgv_select(unknown) does not exist -LINE 1: SELECT pgv_select('test'); - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #3 (free) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test'); -ERROR: function pgv_select(unknown) does not exist -LINE 1: SELECT pgv_select('test'); - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursor test #4 ---- --- non transactional, remove var -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- non transactional, remove pac -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- non transactional, free -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- transactional, remove var -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - --- transactional, remove pack -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - --- transactional, free -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursor test #5 ---- --- non transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -CLOSE r1_cur; -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -CLOSE r1_cur; -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -CLOSE r1_cur; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - ---- ---- Cursor test #6 ---- ---SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); ---BEGIN; ---DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); ---FETCH 1 in r1_cur; ---CLOSE r1_cur; ---SELECT pgv_remove('test', 'x'); ---COMMIT; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Tests for "leaked hash_seq_search scan for hash table" ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -BEGIN; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -BEGIN; -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r2_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r3_cur; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 3 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r2_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r3_cur; - pgv_select ------------- - (1,2) -(1 row) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 3 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; ---- ---- Some special cases ---- --- take #1 -SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); -FETCH 1 in r1_cur; - pgv_select ------------- - (2,2) -(1 row) - -SELECT pgv_remove('test', 'z1'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "z1" -ROLLBACK; -SELECT pgv_select('test', 'z1'); - pgv_select ------------- - (2,2) -(1 row) - --- take #2 -SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); -FETCH 1 in r1_cur; - pgv_select ------------- - (2,2) -(1 row) - -CLOSE r1_cur; -SELECT pgv_remove('test', 'z2'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: cursor "r1_cur" does not exist -ROLLBACK; -SELECT pgv_select('test', 'z2'); -ERROR: unrecognized variable "z2" -SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - --- take #3 -SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -CLOSE r1_cur; -SELECT pgv_remove('test', 'z3'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: cursor "r1_cur" does not exist -ROLLBACK; -SELECT pgv_select('test', 'z3'); - pgv_select ------------- - (1,2) -(1 row) - ---BEGIN; ---DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); ---FETCH 1 in r1_cur; ---SELECT pgv_remove('test', 'z3'); ---COMMIT; ---SELECT pgv_select('test', 'z3'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- take #4 -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SAVEPOINT sp1; -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SAVEPOINT sp1; -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; -BEGIN; -SAVEPOINT sp1; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; ---- ---- Test cases for pgv_stats ---- -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -COMMIT; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); -ERROR: there is a record in the variable "y" with same key -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -ROLLBACK; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); -ERROR: variable "x" already created as TRANSACTIONAL -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -COMMIT; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -ROLLBACK; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Some special cases ---- --- 1 -BEGIN; -SAVEPOINT comm2; -SELECT pgv_insert('test', 'x1', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -COMMIT; --- 2 -BEGIN; -SELECT pgv_insert('test', 'x2', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -SAVEPOINT comm2; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -COMMIT; --- 3 -BEGIN; -SELECT pgv_insert('test', 'x3', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -SAVEPOINT comm2; -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -COMMIT; --- 4 -BEGIN; -SELECT pgv_insert('test', 'x4', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -SAVEPOINT comm2; -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -COMMIT; --- 5 -BEGIN; -SELECT pgv_insert('test', 'x5', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats ------------ - (test,0) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats ------------ - (test,0) -(1 row) - -SAVEPOINT comm2; -COMMIT; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - diff --git a/expected/pg_variables_trans_2.out b/expected/pg_variables_trans_2.out deleted file mode 100644 index a07ad7d..0000000 --- a/expected/pg_variables_trans_2.out +++ /dev/null @@ -1,3764 +0,0 @@ -SET timezone = 'Europe/Moscow'; -- Need to proper output of datetime variables ---CHECK SAVEPOINT RELEASE -BEGIN; --- Declare variables -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'some value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set_int('vars', 'int1', 101, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'int2', 102); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'intNULL', NULL, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str1', 's101', true); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str2', 's102'); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_numeric('vars', 'num1', 1.01, true); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_numeric('vars', 'num2', 1.02); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd2', '2016-03-30'); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); - pgv_set_jsonb ---------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); - pgv_set_jsonb ---------------- - -(1 row) - -SAVEPOINT comm; --- Set new values -SELECT pgv_set('vars', 'any1', 'another value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'another value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set_int('vars', 'int1', 103, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'int2', 103); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'intNULL', 104, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str1', 's103', true); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str2', 's103'); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_numeric('vars', 'num1', 1.03, true); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_numeric('vars', 'num2', 1.03); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 12:00:00', true); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 12:00:00'); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 12:00:00 GMT+03', true); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 12:00:00 GMT+03'); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd1', '2016-04-02', true); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd2', '2016-04-02'); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j1', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}', true); - pgv_set_jsonb ---------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j2', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'); - pgv_set_jsonb ---------------- - -(1 row) - --- Check values before releasing savepoint -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - 104 -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - --- Check values after releasing savepoint -RELEASE comm; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - 104 -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -COMMIT; -CREATE TABLE tab (id int, t varchar); -INSERT INTO tab VALUES (0, 'str00'), (1, 'str33'), (2, NULL), (NULL, 'strNULL'); -BEGIN; -SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -SELECT pgv_insert('vars3', 'r2', tab) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -SAVEPOINT comm; -SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -RELEASE comm; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -COMMIT; ---CHECK SAVEPOINT ROLLBACK -BEGIN; --- Variables are already declared -SAVEPOINT comm2; --- Set new values -SELECT pgv_set('vars', 'any1', 'one more value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'one more value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set_int('vars', 'int1', 101, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'int2', 102); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_int('vars', 'intNULL', NULL, true); - pgv_set_int -------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str1', 's101', true); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_text('vars', 'str2', 's102'); - pgv_set_text --------------- - -(1 row) - -SELECT pgv_set_numeric('vars', 'num1', 1.01, true); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_numeric('vars', 'num2', 1.02); - pgv_set_numeric ------------------ - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); - pgv_set_timestamp -------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); - pgv_set_timestamptz ---------------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_date('vars', 'd2', '2016-03-30'); - pgv_set_date --------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); - pgv_set_jsonb ---------------- - -(1 row) - -SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); - pgv_set_jsonb ---------------- - -(1 row) - --- Check values before rollback to savepoint -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 101 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 102 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s101 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s102 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.01 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.02 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 10:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 11:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 14:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 16:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 03-29-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 03-30-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ---------------------- - [1, 2, "foo", null] -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb --------------------------------------------------- - {"bar": "baz", "active": false, "balance": 7.77} -(1 row) - --- Check values after rollback to savepoint -ROLLBACK TO comm2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get_int('vars', 'int1'); - pgv_get_int -------------- - 103 -(1 row) - -SELECT pgv_get_int('vars', 'int2'); - pgv_get_int -------------- - 102 -(1 row) - -SELECT pgv_get_int('vars', 'intNULL'); - pgv_get_int -------------- - 104 -(1 row) - -SELECT pgv_get_text('vars', 'str1'); - pgv_get_text --------------- - s103 -(1 row) - -SELECT pgv_get_text('vars', 'str2'); - pgv_get_text --------------- - s102 -(1 row) - -SELECT pgv_get_numeric('vars', 'num1'); - pgv_get_numeric ------------------ - 1.03 -(1 row) - -SELECT pgv_get_numeric('vars', 'num2'); - pgv_get_numeric ------------------ - 1.02 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts1'); - pgv_get_timestamp --------------------------- - Wed Mar 30 12:00:00 2016 -(1 row) - -SELECT pgv_get_timestamp('vars', 'ts2'); - pgv_get_timestamp --------------------------- - Wed Mar 30 11:00:00 2016 -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz1'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 18:00:00 2016 MSK -(1 row) - -SELECT pgv_get_timestamptz('vars', 'tstz2'); - pgv_get_timestamptz ------------------------------- - Wed Mar 30 16:00:00 2016 MSK -(1 row) - -SELECT pgv_get_date('vars', 'd1'); - pgv_get_date --------------- - 04-02-2016 -(1 row) - -SELECT pgv_get_date('vars', 'd2'); - pgv_get_date --------------- - 03-30-2016 -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j1'); - pgv_get_jsonb ------------------------------------------------------ - {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} -(1 row) - -SELECT pgv_get_jsonb('vars2', 'j2'); - pgv_get_jsonb --------------------------------------------------- - {"bar": "baz", "active": false, "balance": 7.77} -(1 row) - -COMMIT; --- Record variables -BEGIN; -SAVEPOINT comm2; -SELECT pgv_delete('vars3', 'r1', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_delete('vars3', 'r2', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -ROLLBACK to comm2; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -COMMIT; --- TRYING TO CHANGE FLAG 'IS_TRANSACTIONAL' -SELECT pgv_set('vars', 'any1', 'value'::text); -ERROR: variable "any1" already created as TRANSACTIONAL -SELECT pgv_set('vars', 'any2', 'value'::text, true); -ERROR: variable "any2" already created as NOT TRANSACTIONAL -SELECT pgv_set_int('vars', 'int1', 301); -ERROR: variable "int1" already created as TRANSACTIONAL -SELECT pgv_set_int('vars', 'int2', 302, true); -ERROR: variable "int2" already created as NOT TRANSACTIONAL -SELECT pgv_set_text('vars', 'str1', 's301'); -ERROR: variable "str1" already created as TRANSACTIONAL -SELECT pgv_set_text('vars', 'str2', 's302', true); -ERROR: variable "str2" already created as NOT TRANSACTIONAL -SELECT pgv_set_numeric('vars', 'num1', 3.01); -ERROR: variable "num1" already created as TRANSACTIONAL -SELECT pgv_set_numeric('vars', 'num2', 3.02, true); -ERROR: variable "num2" already created as NOT TRANSACTIONAL -SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 20:00:00'); -ERROR: variable "ts1" already created as TRANSACTIONAL -SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 21:00:00', true); -ERROR: variable "ts2" already created as NOT TRANSACTIONAL -SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 20:00:00 GMT+01'); -ERROR: variable "tstz1" already created as TRANSACTIONAL -SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 21:00:00 GMT+02', true); -ERROR: variable "tstz2" already created as NOT TRANSACTIONAL -SELECT pgv_set_date('vars', 'd1', '2016-04-29'); -ERROR: variable "d1" already created as TRANSACTIONAL -SELECT pgv_set_date('vars', 'd2', '2016-04-30', true); -ERROR: variable "d2" already created as NOT TRANSACTIONAL -SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo2", null]'); -ERROR: variable "j1" already created as TRANSACTIONAL -SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz2", "balance": 7.77, "active": true}', true); -ERROR: variable "j2" already created as NOT TRANSACTIONAL -SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str66' :: varchar)); -ERROR: variable "r1" already created as TRANSACTIONAL -SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str66' :: varchar),true); -ERROR: variable "r2" already created as NOT TRANSACTIONAL --- CHECK pgv_list() WHILE WE HAVE A LOT OF MISCELLANEOUS VARIABLES -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+---------+------------------ - vars | any1 | t - vars | any2 | f - vars | d1 | t - vars | d2 | f - vars | int1 | t - vars | int2 | f - vars | intNULL | t - vars | num1 | t - vars | num2 | f - vars | str1 | t - vars | str2 | f - vars | ts1 | t - vars | ts2 | f - vars | tstz1 | t - vars | tstz2 | f - vars2 | j1 | t - vars2 | j2 | f - vars3 | r1 | t - vars3 | r2 | f -(19 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- VARIABLES DECLARED IN SUBTRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK TO SAVEPOINT --- For better readability we don't use deprecated api functions in test below -BEGIN; -SAVEPOINT sp_to_rollback; -SELECT pgv_set('vars', 'any1', 'text value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'text value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str44' :: varchar), true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str44' :: varchar)); - pgv_insert ------------- - -(1 row) - -ROLLBACK TO sp_to_rollback; -COMMIT; -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized variable "any1" -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ------------- - text value -(1 row) - -SELECT pgv_select('vars3', 'r1'); -ERROR: unrecognized variable "r1" -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (6,str44) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION -BEGIN; -SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp2; -SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------------- - after savepoint sp2 -(1 row) - -ROLLBACK TO sp1; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------------- - before savepoint sp1 -(1 row) - -COMMIT; -BEGIN; -SAVEPOINT sp1; -SAVEPOINT sp2; -SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars2', 'any1',NULL::text); - pgv_get ------------------ - variable exists -(1 row) - -ROLLBACK TO sp1; -COMMIT; -SELECT pgv_get('vars2', 'any1',NULL::text); -ERROR: unrecognized package "vars2" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---CHECK TRANSACTION COMMIT --- Declare variables -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'some value'::text); - pgv_set ---------- - -(1 row) - -BEGIN; --- Set new values -SELECT pgv_set('vars', 'any1', 'another value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'another value'::text); - pgv_set ---------- - -(1 row) - --- Check values before committing transaction -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - --- Check values after committing transaction -COMMIT; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -SELECT pgv_insert('vars3', 'r2', tab) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -BEGIN; -SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -COMMIT; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - --- CHECK TRANSACTION ROLLBACK --- Variables are already declared -BEGIN; --- Set new values -SELECT pgv_set('vars', 'any1', 'one more value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'one more value'::text); - pgv_set ---------- - -(1 row) - --- Check values before rollback -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------- - one more value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - --- Check values after rollback -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------- - another value -(1 row) - -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ----------------- - one more value -(1 row) - --- Record variables -BEGIN; -SELECT pgv_delete('vars3', 'r1', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_delete('vars3', 'r2', 5); - pgv_delete ------------- - t -(1 row) - -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -ROLLBACK; -SELECT pgv_select('vars3', 'r1'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (5,str55) - (0,str00) -(5 rows) - -SELECT pgv_select('vars3', 'r2'); - pgv_select ------------- - (,strNULL) - (1,str33) - (2,) - (0,str00) -(4 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- VARIABLES DECLARED IN TRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK -BEGIN; -SELECT pgv_set('vars', 'any1', 'text value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'any2', 'text value'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_insert('vars', 'r1', row(6 :: integer, 'str44' :: varchar), true); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('vars', 'r2', row(6 :: integer, 'str44' :: varchar)); - pgv_insert ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized variable "any1" -SELECT pgv_get('vars', 'any2',NULL::text); - pgv_get ------------- - text value -(1 row) - -SELECT pgv_select('vars', 'r1'); -ERROR: unrecognized variable "r1" -SELECT pgv_select('vars', 'r2'); - pgv_select ------------- - (6,str44) -(1 row) - -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - --- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION -SELECT pgv_set('vars', 'any1', 'before transaction block'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp2; -SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------------------- - after savepoint sp2 -(1 row) - -ROLLBACK TO sp1; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ----------------------- - before savepoint sp1 -(1 row) - -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get --------------------------- - before transaction block -(1 row) - -BEGIN; -SAVEPOINT sp1; -SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); - pgv_set ---------- - -(1 row) - -RELEASE sp1; -SELECT pgv_get('vars2', 'any1',NULL::text); - pgv_get ------------------ - variable exists -(1 row) - -ROLLBACK; -SELECT pgv_get('vars2', 'any1',NULL::text); -ERROR: unrecognized package "vars2" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- Additional tests -SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; - pgv_insert ------------- - - - - -(4 rows) - -BEGIN; -SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'before savepoint sp1' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_update('vars3', 'r1', row(5 :: integer, 'after savepoint sp1' :: varchar)); - pgv_update ------------- - t -(1 row) - -SAVEPOINT sp2; -SELECT pgv_insert('vars3', 'r1', row(7 :: integer, 'row after sp2 to remove in sp4' :: varchar),true); - pgv_insert ------------- - -(1 row) - -SAVEPOINT sp3; -SAVEPOINT sp4; -SELECT pgv_delete('vars3', 'r1', 7); - pgv_delete ------------- - t -(1 row) - -SAVEPOINT sp5; -SELECT pgv_select('vars3', 'r1'); - pgv_select ---------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) -(5 rows) - -ROLLBACK TO sp5; -SELECT pgv_select('vars3', 'r1'); - pgv_select ---------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) -(5 rows) - -RELEASE sp4; -SELECT pgv_select('vars3', 'r1'); - pgv_select ---------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) -(5 rows) - -ROLLBACK TO sp3; -SELECT pgv_select('vars3', 'r1'); - pgv_select --------------------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) - (7,"row after sp2 to remove in sp4") -(6 rows) - -RELEASE sp2; -SELECT pgv_select('vars3', 'r1'); - pgv_select --------------------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"after savepoint sp1") - (0,str00) - (7,"row after sp2 to remove in sp4") -(6 rows) - -ROLLBACK TO sp1; -SELECT pgv_select('vars3', 'r1'); - pgv_select ----------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"before savepoint sp1") - (0,str00) -(5 rows) - -COMMIT; -SELECT pgv_select('vars3', 'r1'); - pgv_select ----------------------------- - (,strNULL) - (1,str33) - (2,) - (5,"before savepoint sp1") - (0,str00) -(5 rows) - -SELECT pgv_set('vars', 'any1', 'outer'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_set('vars', 'any1', 'begin'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SELECT pgv_set('vars', 'any1', 'sp1'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp2; -SELECT pgv_set('vars', 'any1', 'sp2'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp3; -SAVEPOINT sp4; -SELECT pgv_set('vars', 'any1', 'sp4'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp5; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp4 -(1 row) - -ROLLBACK TO sp5; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp4 -(1 row) - -RELEASE sp4; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp4 -(1 row) - -ROLLBACK TO sp3; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp2 -(1 row) - -RELEASE sp2; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - sp2 -(1 row) - -ROLLBACK TO sp1; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - begin -(1 row) - -ROLLBACK; -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ---------- - outer -(1 row) - -BEGIN; -SELECT pgv_set('vars', 'any1', 'wrong type'::varchar, true); -ERROR: variable "any1" requires "text" value -COMMIT; --- THE REMOVAL OF THE VARIABLE MUST BE CANCELED ON ROLLBACK -SELECT pgv_set('vars', 'any1', 'variable exists'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_remove('vars', 'any1'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - f -(1 row) - -ROLLBACK; -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - t -(1 row) - -SELECT pgv_get('vars', 'any1',NULL::text); - pgv_get ------------------ - variable exists -(1 row) - -BEGIN; -SELECT pgv_remove('vars', 'any1'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - f -(1 row) - -COMMIT; -SELECT pgv_exists('vars', 'any1'); - pgv_exists ------------- - f -(1 row) - -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized package "vars" -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ - vars3 | r1 | t -(1 row) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ - vars3 | r1 | t -(1 row) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -COMMIT; -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -SELECT pgv_set('vars', 'regular', 'regular variable exists'::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars', 'trans1', 'trans1 variable exists'::text, true); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT pgv_free(); -- Check sequential package removal in one subtransaction - pgv_free ----------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -SELECT pgv_set('vars', 'trans2', 'trans2 variable exists'::text, true); - pgv_set ---------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+--------+------------------ - vars | trans2 | t -(1 row) - -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -ROLLBACK; -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+--------+------------------ - vars | trans1 | t -(1 row) - -BEGIN; -SAVEPOINT sp1; -SAVEPOINT sp2; -SAVEPOINT sp3; -SELECT pgv_set('vars2', 'trans2', 'trans2 variable exists'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp4; -SAVEPOINT sp5; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars - vars2 -(2 rows) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -RELEASE sp5; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars - vars2 -(2 rows) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -RELEASE sp4; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars - vars2 -(2 rows) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -COMMIT; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - -BEGIN; -SELECT pgv_set('vars', 'trans1', 'package created'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -SELECT pgv_set('vars', 'trans1', 'package restored'::text, true); - pgv_set ---------- - -(1 row) - -SELECT * FROM pgv_list() ORDER BY package, name; - package | name | is_transactional ----------+--------+------------------ - vars | trans1 | t -(1 row) - -COMMIT; -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - --- REMOVED TRANSACTIONAL VARIABLE SHOULD BE NOT ACCESSIBLE THROUGH LastVariable -SELECT pgv_insert('package', 'errs',row(n), true) -FROM generate_series(1,5) AS gs(n) WHERE 1.0/(n-3)<>0; -ERROR: division by zero -SELECT pgv_insert('package', 'errs',row(1), true); - pgv_insert ------------- - -(1 row) - --- Variable should not exists in case when error occurs during creation -SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); -ERROR: could not identify a hash function for type unknown -SELECT pgv_select('vars4', 'r1', 0); -ERROR: unrecognized package "vars4" --- If variable created and removed in same transaction level, --- it should be totally removed and should not be present --- in changes list and cache. -BEGIN; -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT comm; -SELECT pgv_remove('vars', 'any1'); - pgv_remove ------------- - -(1 row) - -RELEASE comm; -SELECT pgv_get('vars', 'any1',NULL::text); -ERROR: unrecognized package "vars" -COMMIT; --- Tests for PGPRO-2440 -SELECT pgv_insert('vars3', 'r3', row(1 :: integer, NULL::varchar), true); - pgv_insert ------------- - -(1 row) - -BEGIN; -SELECT pgv_insert('vars3', 'r3', row(2 :: integer, NULL::varchar), true); - pgv_insert ------------- - -(1 row) - -SAVEPOINT comm; -SELECT pgv_insert('vars3', 'r3', row(3 :: integer, NULL::varchar), true); - pgv_insert ------------- - -(1 row) - -COMMIT; -SELECT pgv_delete('vars3', 'r3', 3); - pgv_delete ------------- - t -(1 row) - -BEGIN; -SELECT pgv_set('vars1', 't1', ''::text); - pgv_set ---------- - -(1 row) - -SELECT pgv_set('vars2', 't2', ''::text, true); - pgv_set ---------- - -(1 row) - -SAVEPOINT sp1; -SAVEPOINT sp2; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ERROR; -ERROR: syntax error at or near "ERROR" -LINE 1: ERROR; - ^ -COMMIT; -BEGIN; -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SAVEPOINT sp_to_rollback; -SELECT pgv_set('vars', 'any1', 'some value'::text, true); - pgv_set ---------- - -(1 row) - -ROLLBACK TO sp_to_rollback; -COMMIT; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - --- Package should exist after rollback if it contains regular variable -BEGIN; -SELECT pgv_set('vars', 'any1', 'some value'::text); - pgv_set ---------- - -(1 row) - -ROLLBACK; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars -(1 row) - --- Package should not exist if it becomes empty in rolled back transaction -BEGIN; -SAVEPOINT comm2; -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -ROLLBACK TO comm2; -SELECT pgv_exists('vars'); - pgv_exists ------------- - f -(1 row) - -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- - vars -(1 row) - -COMMIT; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - -SELECT pgv_set('vars', 'any1', 'some value'::text); - pgv_set ---------- - -(1 row) - -BEGIN; -SELECT pgv_remove('vars'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT package FROM pgv_stats() ORDER BY package; - package ---------- -(0 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- Variables should be insertable after pgv_remove (variable) -BEGIN; -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -ROLLBACK; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -BEGIN; -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -COMMIT; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | x | t -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - --- Variables should be insertable after pgv_remove (package) -BEGIN; -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -ROLLBACK; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | x | t -(1 row) - -BEGIN; -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -COMMIT; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | y | t -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - --- Variables should be insertable after pgv_free -BEGIN; -SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -ROLLBACK; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | y | t -(1 row) - -BEGIN; -SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) -(1 row) - -SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -COMMIT; -SELECT * FROM pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - test | z | t -(1 row) - -SELECT pgv_select('test', 'z'); - pgv_select ------------- - (1,3) - (2,4) -(2 rows) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- Variables should be rollbackable if transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - ---- ---- Variables should not be rollbackable if not transactional ---- --- case 1 (remove var) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- case 2 (remove pack) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- case 3 (free) -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -BEGIN; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" --- clear all -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #1 (remove var) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "y" -ROLLBACK; -SELECT pgv_select('test', 'y'); -ERROR: unrecognized variable "y" -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #2 (remove pack) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test'); -ERROR: function pgv_select(unknown) does not exist -LINE 1: SELECT pgv_select('test'); - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursors test #3 (free) ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test'); -ERROR: function pgv_select(unknown) does not exist -LINE 1: SELECT pgv_select('test'); - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursor test #4 ---- --- non transactional, remove var -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- non transactional, remove pac -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- non transactional, free -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- transactional, remove var -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test', 'y'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - --- transactional, remove pack -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - --- transactional, free -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'y'); - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Cursor test #5 ---- --- non transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -CLOSE r1_cur; -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -CLOSE r1_cur; -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -CLOSE r1_cur; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -ROLLBACK; -SELECT pgv_select('test', 'x'); -ERROR: unrecognized package "test" --- transactional -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test', 'x'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_remove('test'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized package "test" -ROLLBACK; -SELECT pgv_select('test', 'x'); - pgv_select ------------- - (1,2) -(1 row) - ---- ---- Cursor test #6 ---- ---SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); ---BEGIN; ---DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); ---FETCH 1 in r1_cur; ---CLOSE r1_cur; ---SELECT pgv_remove('test', 'x'); ---COMMIT; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Tests for "leaked hash_seq_search scan for hash table" ---- -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -BEGIN; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'x') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'x') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -BEGIN; -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -SELECT pgv_select('test', 'y') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -SELECT pgv_select('test', 'y') LIMIT 2; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -SELECT pgv_select('test', 'y') LIMIT 3; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r2_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r3_cur; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 3 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r2_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 1 in r3_cur; - pgv_select ------------- - (1,2) -(1 row) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 2 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 3 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -ROLLBACK; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); -DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -FETCH 2 in r2_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -FETCH 3 in r3_cur; - pgv_select ------------- - (1,2) - (2,3) - (3,4) -(3 rows) - -COMMIT; ---- ---- Some special cases ---- --- take #1 -SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); -FETCH 1 in r1_cur; - pgv_select ------------- - (2,2) -(1 row) - -SELECT pgv_remove('test', 'z1'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: unrecognized variable "z1" -ROLLBACK; -SELECT pgv_select('test', 'z1'); - pgv_select ------------- - (2,2) -(1 row) - --- take #2 -SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); -FETCH 1 in r1_cur; - pgv_select ------------- - (2,2) -(1 row) - -CLOSE r1_cur; -SELECT pgv_remove('test', 'z2'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: cursor "r1_cur" does not exist -ROLLBACK; -SELECT pgv_select('test', 'z2'); -ERROR: unrecognized variable "z2" -SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); - pgv_insert ------------- - -(1 row) - --- take #3 -SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -CLOSE r1_cur; -SELECT pgv_remove('test', 'z3'); - pgv_remove ------------- - -(1 row) - -FETCH 1 in r1_cur; -ERROR: cursor "r1_cur" does not exist -ROLLBACK; -SELECT pgv_select('test', 'z3'); - pgv_select ------------- - (1,2) -(1 row) - ---BEGIN; ---DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); ---FETCH 1 in r1_cur; ---SELECT pgv_remove('test', 'z3'); ---COMMIT; ---SELECT pgv_select('test', 'z3'); -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - --- take #4 -SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SAVEPOINT sp1; -FETCH 1 in r1_cur; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); -SAVEPOINT sp1; -FETCH 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; -BEGIN; -SAVEPOINT sp1; -SELECT pgv_select('test', 'x') LIMIT 1; - pgv_select ------------- - (1,2) -(1 row) - -ROLLBACK TO SAVEPOINT sp1; -COMMIT; ---- ---- Test cases for pgv_stats ---- -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -COMMIT; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); -ERROR: there is a record in the variable "y" with same key -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -ROLLBACK; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); -ERROR: variable "x" already created as TRANSACTIONAL -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -COMMIT; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,32768) -(1 row) - -ROLLBACK; -SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); -ERROR: variable "y" already created as TRANSACTIONAL -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - ---- ---- Some special cases ---- --- 1 -BEGIN; -SAVEPOINT comm2; -SELECT pgv_insert('test', 'x1', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,24576) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,24576) -(1 row) - -COMMIT; --- 2 -BEGIN; -SELECT pgv_insert('test', 'x2', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -SAVEPOINT comm2; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,40960) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,40960) -(1 row) - -COMMIT; --- 3 -BEGIN; -SELECT pgv_insert('test', 'x3', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -SAVEPOINT comm2; -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,57344) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,57344) -(1 row) - -COMMIT; --- 4 -BEGIN; -SELECT pgv_insert('test', 'x4', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,73728) -(1 row) - -SAVEPOINT comm2; -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,73728) -(1 row) - -COMMIT; --- 5 -BEGIN; -SELECT pgv_insert('test', 'x5', ROW (2::float, 1::float), TRUE); - pgv_insert ------------- - -(1 row) - -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); -FETCH 1 in r1_cur; - pgv_stats --------------- - (test,90112) -(1 row) - -FETCH 1 in r2_cur; - pgv_stats --------------- - (test,90112) -(1 row) - -SAVEPOINT comm2; -COMMIT; -SELECT pgv_free(); - pgv_free ----------- - -(1 row) - diff --git a/sql/pg_variables_trans.sql b/sql/pg_variables_trans.sql index 8cb1d2f..0d67ae1 100644 --- a/sql/pg_variables_trans.sql +++ b/sql/pg_variables_trans.sql @@ -1037,11 +1037,22 @@ COMMIT; --- --- Test cases for pgv_stats --- +--- Amount of allocated memory may vary from version to version, as well as from +--- platform to platform. Moreover, postgres versions less than 90600 always +--- show zero allocated memory. So, it's much easier to check if allocated +--- memory size is multiple of 8k since we use ALLOCSET_DEFAULT_INITSIZE +--- (see memutils.h), insted of creating multiple outputs files. +--- +CREATE TEMP VIEW pgv_stats_view(pack, mem_mult) AS + SELECT package, allocated_memory % 8192 as allocated_multiple_8192 + FROM pgv_stats() + ORDER BY 1; + SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; FETCH 1 in r2_cur; COMMIT; @@ -1049,8 +1060,8 @@ COMMIT; SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; FETCH 1 in r2_cur; ROLLBACK; @@ -1060,8 +1071,8 @@ SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; FETCH 1 in r2_cur; COMMIT; @@ -1069,8 +1080,8 @@ COMMIT; SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); BEGIN; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; FETCH 1 in r2_cur; ROLLBACK; @@ -1086,8 +1097,8 @@ SELECT pgv_free(); BEGIN; SAVEPOINT comm2; SELECT pgv_insert('test', 'x1', ROW (2::float, 1::float), TRUE); -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; FETCH 1 in r2_cur; COMMIT; @@ -1096,8 +1107,8 @@ COMMIT; BEGIN; SELECT pgv_insert('test', 'x2', ROW (2::float, 1::float), TRUE); SAVEPOINT comm2; -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; FETCH 1 in r2_cur; COMMIT; @@ -1105,8 +1116,8 @@ COMMIT; -- 3 BEGIN; SELECT pgv_insert('test', 'x3', ROW (2::float, 1::float), TRUE); -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; SAVEPOINT comm2; FETCH 1 in r1_cur; FETCH 1 in r2_cur; @@ -1115,8 +1126,8 @@ COMMIT; -- 4 BEGIN; SELECT pgv_insert('test', 'x4', ROW (2::float, 1::float), TRUE); -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; SAVEPOINT comm2; FETCH 1 in r2_cur; @@ -1125,11 +1136,12 @@ COMMIT; -- 5 BEGIN; SELECT pgv_insert('test', 'x5', ROW (2::float, 1::float), TRUE); -DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); -DECLARE r2_cur CURSOR FOR SELECT pgv_stats(); +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; FETCH 1 in r1_cur; FETCH 1 in r2_cur; SAVEPOINT comm2; COMMIT; +DROP VIEW pgv_stats_view; SELECT pgv_free(); From 6a62ec605b5b5cee72cf1697304032641a44f862 Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Fri, 27 Nov 2020 13:39:54 +0300 Subject: [PATCH 12/46] Use more detailed message in record insert error. In case of inserting a erroneous record in variable show clear messages, if it is amount of fields or fields types are wrong. --- expected/pg_variables.out | 6 +++--- pg_variables_record.c | 11 +++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/expected/pg_variables.out b/expected/pg_variables.out index ba0b64a..2e67ab4 100644 --- a/expected/pg_variables.out +++ b/expected/pg_variables.out @@ -563,11 +563,11 @@ ERROR: variable "j1" requires "jsonb" value SELECT pgv_insert('vars3', 'r1', tab) FROM tab; ERROR: there is a record in the variable "r1" with same key SELECT pgv_insert('vars3', 'r1', row(1, 'str1', 'str2')); -ERROR: new record structure differs from variable "r1" structure +ERROR: new record structure have 3 attributes, but variable "r1" structure have 2. SELECT pgv_insert('vars3', 'r1', row(1, 1)); -ERROR: new record structure differs from variable "r1" structure +ERROR: new record attribute type for attribute number 2 differs from variable "r1" structure. You may need explicit type casts. SELECT pgv_insert('vars3', 'r1', row('str1', 'str1')); -ERROR: new record structure differs from variable "r1" structure +ERROR: new record attribute type for attribute number 1 differs from variable "r1" structure. You may need explicit type casts. SELECT pgv_select('vars3', 'r1', ARRAY[[1,2]]); -- fail ERROR: searching for elements in multidimensional arrays is not supported -- Test variables caching diff --git a/pg_variables_record.c b/pg_variables_record.c index b97ffca..d34d12c 100644 --- a/pg_variables_record.c +++ b/pg_variables_record.c @@ -188,8 +188,9 @@ check_attributes(Variable *variable, TupleDesc tupdesc) if (record->tupdesc->natts != tupdesc->natts) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("new record structure differs from variable \"%s\" " - "structure", GetName(variable)))); + errmsg("new record structure have %d attributes, but variable " + "\"%s\" structure have %d.", + tupdesc->natts, GetName(variable), record->tupdesc->natts))); /* Second, check columns type. */ for (i = 0; i < tupdesc->natts; i++) @@ -202,8 +203,10 @@ check_attributes(Variable *variable, TupleDesc tupdesc) || (attr1->atttypmod != attr2->atttypmod)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("new record structure differs from variable \"%s\" " - "structure", GetName(variable)))); + errmsg("new record attribute type for attribute number %d " + "differs from variable \"%s\" structure. You may " + "need explicit type casts.", + i + 1, GetName(variable)))); } } From 4408d5adc7304666a1db051379cf71e9ff7677c2 Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Fri, 27 Nov 2020 14:46:52 +0300 Subject: [PATCH 13/46] Minor refactoring for insert deleted variable. --- pg_variables.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/pg_variables.c b/pg_variables.c index 4bd6bdd..0350a85 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -696,13 +696,15 @@ variable_insert(PG_FUNCTION_ARGS) tupTypmod = HeapTupleHeaderGetTypMod(rec); record = &(GetActualValue(variable).record); - if (!record->tupdesc) + tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); + + if (!record->tupdesc || variable->is_deleted) { /* * This is the first record for the var_name. Initialize record. */ - tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); init_record(record, tupdesc, variable); + variable->is_deleted = false; } else if (LastTypeId == RECORDOID || !OidIsValid(LastTypeId) || LastTypeId != tupType) @@ -711,16 +713,7 @@ variable_insert(PG_FUNCTION_ARGS) * We need to check attributes of the new row if this is a transient * record type or if last record has different id. */ - tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); - if (variable->is_deleted) - { - init_record(record, tupdesc, variable); - variable->is_deleted = false; - } - else - { - check_attributes(variable, tupdesc); - } + check_attributes(variable, tupdesc); } LastTypeId = tupType; From 1b37d6629e89d0b3105eb56f1e86ccfd0c794e62 Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Wed, 2 Dec 2020 16:22:11 +0300 Subject: [PATCH 14/46] Fix error on insert from table #32 --- expected/pg_variables.out | 56 +++++++++++++++++++++++++++++++++ expected/pg_variables_trans.out | 56 +++++++++++++++++++++++++++++++++ pg_variables.c | 23 +++----------- sql/pg_variables.sql | 16 ++++++++++ sql/pg_variables_trans.sql | 18 +++++++++++ 5 files changed, 151 insertions(+), 18 deletions(-) diff --git a/expected/pg_variables.out b/expected/pg_variables.out index 2e67ab4..e21ec67 100644 --- a/expected/pg_variables.out +++ b/expected/pg_variables.out @@ -929,3 +929,59 @@ SELECT * FROM pgv_list() order by package, name; ---------+------+------------------ (0 rows) +-- Check insert of record with various amount of fields +CREATE TEMP TABLE foo(id int, t text); +INSERT INTO foo VALUES (0, 'str00'); +SELECT pgv_insert('vars', 'r1', row(1, 'str1'::text, 'str2'::text)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars', 'r1'); + pgv_select +--------------- + (1,str1,str2) +(1 row) + +SELECT pgv_insert('vars', 'r1', foo) FROM foo; +ERROR: new record structure have 2 attributes, but variable "r1" structure have 3. +SELECT pgv_select('vars', 'r1'); + pgv_select +--------------- + (1,str1,str2) +(1 row) + +SELECT pgv_insert('vars', 'r2', row(1, 'str1')); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r2', foo) FROM foo; +ERROR: new record attribute type for attribute number 2 differs from variable "r2" structure. You may need explicit type casts. +SELECT pgv_select('vars', 'r2'); + pgv_select +------------ + (1,str1) +(1 row) + +SELECT pgv_insert('vars', 'r3', row(1, 'str1'::text)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r3', foo) FROM foo; + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars', 'r3'); + pgv_select +------------ + (1,str1) + (0,str00) +(2 rows) + diff --git a/expected/pg_variables_trans.out b/expected/pg_variables_trans.out index 2389efa..2f46e04 100644 --- a/expected/pg_variables_trans.out +++ b/expected/pg_variables_trans.out @@ -3773,3 +3773,59 @@ SELECT pgv_free(); (1 row) +--- +--- Test case for issue #32 [PGPRO-4456] +--- +CREATE TEMP TABLE tab (id int, t varchar); +INSERT INTO tab VALUES (0, 'str00'); +SELECT pgv_insert('vars', 'r1', row(1, 'str1', 'str2')); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'a', tab) FROM tab; + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r1', tab) FROM tab; +ERROR: new record structure have 2 attributes, but variable "r1" structure have 3. +SELECT pgv_select('vars', 'r1'); + pgv_select +--------------- + (1,str1,str2) +(1 row) + +SELECT pgv_insert('vars', 'r2', row(1, 'str1'::varchar)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'b', tab) FROM tab; + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r2', tab) FROM tab; + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars', 'r2'); + pgv_select +------------ + (1,str1) + (0,str00) +(2 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/pg_variables.c b/pg_variables.c index 0350a85..b75701a 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -121,8 +121,6 @@ static MemoryContext ModuleContext = NULL; static Package *LastPackage = NULL; /* Recent variable */ static Variable *LastVariable = NULL; -/* Recent row type id */ -static Oid LastTypeId = InvalidOid; /* Saved hook values for recall */ static ExecutorEnd_hook_type prev_ExecutorEnd = NULL; @@ -706,8 +704,7 @@ variable_insert(PG_FUNCTION_ARGS) init_record(record, tupdesc, variable); variable->is_deleted = false; } - else if (LastTypeId == RECORDOID || !OidIsValid(LastTypeId) || - LastTypeId != tupType) + else { /* * We need to check attributes of the new row if this is a transient @@ -716,8 +713,6 @@ variable_insert(PG_FUNCTION_ARGS) check_attributes(variable, tupdesc); } - LastTypeId = tupType; - insert_record(variable, rec); /* Release resources */ @@ -742,6 +737,7 @@ variable_update(PG_FUNCTION_ARGS) bool res; Oid tupType; int32 tupTypmod; + TupleDesc tupdesc = NULL; /* Checks */ CHECK_ARGS_FOR_NULL(); @@ -794,17 +790,9 @@ variable_update(PG_FUNCTION_ARGS) tupType = HeapTupleHeaderGetTypeId(rec); tupTypmod = HeapTupleHeaderGetTypMod(rec); - if (LastTypeId == RECORDOID || !OidIsValid(LastTypeId) || - LastTypeId != tupType) - { - TupleDesc tupdesc = NULL; - - tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); - check_attributes(variable, tupdesc); - ReleaseTupleDesc(tupdesc); - } - - LastTypeId = tupType; + tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); + check_attributes(variable, tupdesc); + ReleaseTupleDesc(tupdesc); res = update_record(variable, rec); @@ -1330,7 +1318,6 @@ resetVariablesCache(void) /* Remove package and variable from cache */ LastPackage = NULL; LastVariable = NULL; - LastTypeId = InvalidOid; } /* diff --git a/sql/pg_variables.sql b/sql/pg_variables.sql index a9fdbbd..bad7976 100644 --- a/sql/pg_variables.sql +++ b/sql/pg_variables.sql @@ -259,3 +259,19 @@ SELECT pgv_free(); SELECT pgv_exists('vars'); SELECT * FROM pgv_list() order by package, name; +-- Check insert of record with various amount of fields +CREATE TEMP TABLE foo(id int, t text); +INSERT INTO foo VALUES (0, 'str00'); + +SELECT pgv_insert('vars', 'r1', row(1, 'str1'::text, 'str2'::text)); +SELECT pgv_select('vars', 'r1'); +SELECT pgv_insert('vars', 'r1', foo) FROM foo; +SELECT pgv_select('vars', 'r1'); + +SELECT pgv_insert('vars', 'r2', row(1, 'str1')); +SELECT pgv_insert('vars', 'r2', foo) FROM foo; +SELECT pgv_select('vars', 'r2'); + +SELECT pgv_insert('vars', 'r3', row(1, 'str1'::text)); +SELECT pgv_insert('vars', 'r3', foo) FROM foo; +SELECT pgv_select('vars', 'r3'); diff --git a/sql/pg_variables_trans.sql b/sql/pg_variables_trans.sql index 0d67ae1..72d9559 100644 --- a/sql/pg_variables_trans.sql +++ b/sql/pg_variables_trans.sql @@ -1145,3 +1145,21 @@ COMMIT; DROP VIEW pgv_stats_view; SELECT pgv_free(); + +--- +--- Test case for issue #32 [PGPRO-4456] +--- +CREATE TEMP TABLE tab (id int, t varchar); +INSERT INTO tab VALUES (0, 'str00'); + +SELECT pgv_insert('vars', 'r1', row(1, 'str1', 'str2')); +SELECT pgv_insert('vars', 'a', tab) FROM tab; +SELECT pgv_insert('vars', 'r1', tab) FROM tab; +SELECT pgv_select('vars', 'r1'); + +SELECT pgv_insert('vars', 'r2', row(1, 'str1'::varchar)); +SELECT pgv_insert('vars', 'b', tab) FROM tab; +SELECT pgv_insert('vars', 'r2', tab) FROM tab; +SELECT pgv_select('vars', 'r2'); + +SELECT pgv_free(); From 2e3f14f194c9ff2f420cb6fb94628f6671b0361f Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Wed, 9 Dec 2020 14:09:16 +0300 Subject: [PATCH 15/46] Use hint instead of long message #32 --- expected/pg_variables.out | 9 ++++++--- pg_variables_record.c | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/expected/pg_variables.out b/expected/pg_variables.out index e21ec67..180ebd1 100644 --- a/expected/pg_variables.out +++ b/expected/pg_variables.out @@ -565,9 +565,11 @@ ERROR: there is a record in the variable "r1" with same key SELECT pgv_insert('vars3', 'r1', row(1, 'str1', 'str2')); ERROR: new record structure have 3 attributes, but variable "r1" structure have 2. SELECT pgv_insert('vars3', 'r1', row(1, 1)); -ERROR: new record attribute type for attribute number 2 differs from variable "r1" structure. You may need explicit type casts. +ERROR: new record attribute type for attribute number 2 differs from variable "r1" structure. +HINT: You may need explicit type casts. SELECT pgv_insert('vars3', 'r1', row('str1', 'str1')); -ERROR: new record attribute type for attribute number 1 differs from variable "r1" structure. You may need explicit type casts. +ERROR: new record attribute type for attribute number 1 differs from variable "r1" structure. +HINT: You may need explicit type casts. SELECT pgv_select('vars3', 'r1', ARRAY[[1,2]]); -- fail ERROR: searching for elements in multidimensional arrays is not supported -- Test variables caching @@ -959,7 +961,8 @@ SELECT pgv_insert('vars', 'r2', row(1, 'str1')); (1 row) SELECT pgv_insert('vars', 'r2', foo) FROM foo; -ERROR: new record attribute type for attribute number 2 differs from variable "r2" structure. You may need explicit type casts. +ERROR: new record attribute type for attribute number 2 differs from variable "r2" structure. +HINT: You may need explicit type casts. SELECT pgv_select('vars', 'r2'); pgv_select ------------ diff --git a/pg_variables_record.c b/pg_variables_record.c index d34d12c..3d7ca18 100644 --- a/pg_variables_record.c +++ b/pg_variables_record.c @@ -204,9 +204,9 @@ check_attributes(Variable *variable, TupleDesc tupdesc) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("new record attribute type for attribute number %d " - "differs from variable \"%s\" structure. You may " - "need explicit type casts.", - i + 1, GetName(variable)))); + "differs from variable \"%s\" structure.", + i + 1, GetName(variable)), + errhint("You may need explicit type casts."))); } } From c8178943f1f8021ab1705abb5ee306ccfba0c9e3 Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Thu, 4 Feb 2021 15:48:51 +0300 Subject: [PATCH 16/46] Issue #38: fix backand crash on nonhashable row insert. --- expected/pg_variables_trans.out | 5 +++++ pg_variables.c | 8 ++++++++ sql/pg_variables_trans.sql | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/expected/pg_variables_trans.out b/expected/pg_variables_trans.out index 2f46e04..6cede44 100644 --- a/expected/pg_variables_trans.out +++ b/expected/pg_variables_trans.out @@ -3829,3 +3829,8 @@ SELECT pgv_free(); (1 row) +-- +-- Test case for issue #38 [PGPRO-4676] +-- +SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE); +ERROR: could not identify a hash function for type record diff --git a/pg_variables.c b/pg_variables.c index b75701a..5e7156e 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -2116,6 +2116,14 @@ rollbackSavepoint(TransObject *object, TransObjectType type) { TransState *state; + /* Nothing to do here if trans object was removed already. */ + if (dlist_is_empty(&object->states)) + { + /* Probably redundant. */ + removeObject(object, type); + return; + } + state = GetActualState(object); removeState(object, type, state); diff --git a/sql/pg_variables_trans.sql b/sql/pg_variables_trans.sql index 72d9559..7deef59 100644 --- a/sql/pg_variables_trans.sql +++ b/sql/pg_variables_trans.sql @@ -1163,3 +1163,9 @@ SELECT pgv_insert('vars', 'r2', tab) FROM tab; SELECT pgv_select('vars', 'r2'); SELECT pgv_free(); + + +-- +-- Test case for issue #38 [PGPRO-4676] +-- +SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE); From 2a38b715170c1016b14783bebcd5eec497c9732f Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Mon, 8 Feb 2021 12:39:54 +0300 Subject: [PATCH 17/46] Issue #38: remove useless comment. --- pg_variables.c | 1 - 1 file changed, 1 deletion(-) diff --git a/pg_variables.c b/pg_variables.c index 5e7156e..152b5d6 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -2119,7 +2119,6 @@ rollbackSavepoint(TransObject *object, TransObjectType type) /* Nothing to do here if trans object was removed already. */ if (dlist_is_empty(&object->states)) { - /* Probably redundant. */ removeObject(object, type); return; } From 8521406d5e81401ac934d495cd2eed48d2fc9e23 Mon Sep 17 00:00:00 2001 From: Roman Zharkov Date: Tue, 16 Mar 2021 15:32:53 +0700 Subject: [PATCH 18/46] Remove extra double quotes in the extension name. --- pg_variables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pg_variables.c b/pg_variables.c index 152b5d6..d76e01f 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -2494,7 +2494,7 @@ compatibility_check(void) if (!pg_compatibility_check_no_error()) freeStatsLists(); - PG_COMPATIBILITY_CHECK("pg_variables"); + PG_COMPATIBILITY_CHECK(pg_variables); } # endif /* PG_COMPATIBILITY_CHECK */ # endif /* PG_VERSION_NUM */ From 2806cf758eb9b20aa94e79df650503d0cfb37d2a Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Wed, 23 Jun 2021 17:28:33 +0300 Subject: [PATCH 19/46] Add support for PostgreSQL 14. --- expected/pg_variables_trans_0.out | 3840 +++++++++++++++++++++++++++++ pg_variables.c | 16 +- 2 files changed, 3853 insertions(+), 3 deletions(-) create mode 100644 expected/pg_variables_trans_0.out diff --git a/expected/pg_variables_trans_0.out b/expected/pg_variables_trans_0.out new file mode 100644 index 0000000..7c29138 --- /dev/null +++ b/expected/pg_variables_trans_0.out @@ -0,0 +1,3840 @@ +SET timezone = 'Europe/Moscow'; -- Need to proper output of datetime variables +--CHECK SAVEPOINT RELEASE +BEGIN; +-- Declare variables +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'some value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 101, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 102); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', NULL, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's101', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's102'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.01, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.02); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-03-30'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); + pgv_set_jsonb +--------------- + +(1 row) + +SAVEPOINT comm; +-- Set new values +SELECT pgv_set('vars', 'any1', 'another value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'another value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 103, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 103); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', 104, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's103', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's103'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.03, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.03); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 12:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 12:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 12:00:00 GMT+03', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 12:00:00 GMT+03'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-04-02', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-04-02'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'); + pgv_set_jsonb +--------------- + +(1 row) + +-- Check values before releasing savepoint +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +-- Check values after releasing savepoint +RELEASE comm; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +COMMIT; +CREATE TABLE tab (id int, t varchar); +INSERT INTO tab VALUES (0, 'str00'), (1, 'str33'), (2, NULL), (NULL, 'strNULL'); +BEGIN; +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SELECT pgv_insert('vars3', 'r2', tab) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SAVEPOINT comm; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +RELEASE comm; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +COMMIT; +--CHECK SAVEPOINT ROLLBACK +BEGIN; +-- Variables are already declared +SAVEPOINT comm2; +-- Set new values +SELECT pgv_set('vars', 'any1', 'one more value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'one more value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set_int('vars', 'int1', 101, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'int2', 102); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_int('vars', 'intNULL', NULL, true); + pgv_set_int +------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str1', 's101', true); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_text('vars', 'str2', 's102'); + pgv_set_text +-------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num1', 1.01, true); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_numeric('vars', 'num2', 1.02); + pgv_set_numeric +----------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 10:00:00', true); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 11:00:00'); + pgv_set_timestamp +------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 10:00:00 GMT+01', true); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 11:00:00 GMT+02'); + pgv_set_timestamptz +--------------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd1', '2016-03-29', true); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_date('vars', 'd2', '2016-03-30'); + pgv_set_date +-------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo", null]', true); + pgv_set_jsonb +--------------- + +(1 row) + +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz", "balance": 7.77, "active": false}'); + pgv_set_jsonb +--------------- + +(1 row) + +-- Check values before rollback to savepoint +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 101 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 102 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s101 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s102 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.01 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.02 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 10:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 11:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 14:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 16:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 03-29-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 03-30-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +--------------------- + [1, 2, "foo", null] +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +-------------------------------------------------- + {"bar": "baz", "active": false, "balance": 7.77} +(1 row) + +-- Check values after rollback to savepoint +ROLLBACK TO comm2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get_int('vars', 'int1'); + pgv_get_int +------------- + 103 +(1 row) + +SELECT pgv_get_int('vars', 'int2'); + pgv_get_int +------------- + 102 +(1 row) + +SELECT pgv_get_int('vars', 'intNULL'); + pgv_get_int +------------- + 104 +(1 row) + +SELECT pgv_get_text('vars', 'str1'); + pgv_get_text +-------------- + s103 +(1 row) + +SELECT pgv_get_text('vars', 'str2'); + pgv_get_text +-------------- + s102 +(1 row) + +SELECT pgv_get_numeric('vars', 'num1'); + pgv_get_numeric +----------------- + 1.03 +(1 row) + +SELECT pgv_get_numeric('vars', 'num2'); + pgv_get_numeric +----------------- + 1.02 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts1'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 12:00:00 2016 +(1 row) + +SELECT pgv_get_timestamp('vars', 'ts2'); + pgv_get_timestamp +-------------------------- + Wed Mar 30 11:00:00 2016 +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz1'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 18:00:00 2016 MSK +(1 row) + +SELECT pgv_get_timestamptz('vars', 'tstz2'); + pgv_get_timestamptz +------------------------------ + Wed Mar 30 16:00:00 2016 MSK +(1 row) + +SELECT pgv_get_date('vars', 'd1'); + pgv_get_date +-------------- + 04-02-2016 +(1 row) + +SELECT pgv_get_date('vars', 'd2'); + pgv_get_date +-------------- + 03-30-2016 +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j1'); + pgv_get_jsonb +----------------------------------------------------- + {"foo": [true, "bar"], "tags": {"a": 1, "b": null}} +(1 row) + +SELECT pgv_get_jsonb('vars2', 'j2'); + pgv_get_jsonb +-------------------------------------------------- + {"bar": "baz", "active": false, "balance": 7.77} +(1 row) + +COMMIT; +-- Record variables +BEGIN; +SAVEPOINT comm2; +SELECT pgv_delete('vars3', 'r1', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_delete('vars3', 'r2', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +ROLLBACK to comm2; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +COMMIT; +-- TRYING TO CHANGE FLAG 'IS_TRANSACTIONAL' +SELECT pgv_set('vars', 'any1', 'value'::text); +ERROR: variable "any1" already created as TRANSACTIONAL +SELECT pgv_set('vars', 'any2', 'value'::text, true); +ERROR: variable "any2" already created as NOT TRANSACTIONAL +SELECT pgv_set_int('vars', 'int1', 301); +ERROR: variable "int1" already created as TRANSACTIONAL +SELECT pgv_set_int('vars', 'int2', 302, true); +ERROR: variable "int2" already created as NOT TRANSACTIONAL +SELECT pgv_set_text('vars', 'str1', 's301'); +ERROR: variable "str1" already created as TRANSACTIONAL +SELECT pgv_set_text('vars', 'str2', 's302', true); +ERROR: variable "str2" already created as NOT TRANSACTIONAL +SELECT pgv_set_numeric('vars', 'num1', 3.01); +ERROR: variable "num1" already created as TRANSACTIONAL +SELECT pgv_set_numeric('vars', 'num2', 3.02, true); +ERROR: variable "num2" already created as NOT TRANSACTIONAL +SELECT pgv_set_timestamp('vars', 'ts1', '2016-03-30 20:00:00'); +ERROR: variable "ts1" already created as TRANSACTIONAL +SELECT pgv_set_timestamp('vars', 'ts2', '2016-03-30 21:00:00', true); +ERROR: variable "ts2" already created as NOT TRANSACTIONAL +SELECT pgv_set_timestamptz('vars', 'tstz1', '2016-03-30 20:00:00 GMT+01'); +ERROR: variable "tstz1" already created as TRANSACTIONAL +SELECT pgv_set_timestamptz('vars', 'tstz2', '2016-03-30 21:00:00 GMT+02', true); +ERROR: variable "tstz2" already created as NOT TRANSACTIONAL +SELECT pgv_set_date('vars', 'd1', '2016-04-29'); +ERROR: variable "d1" already created as TRANSACTIONAL +SELECT pgv_set_date('vars', 'd2', '2016-04-30', true); +ERROR: variable "d2" already created as NOT TRANSACTIONAL +SELECT pgv_set_jsonb('vars2', 'j1', '[1, 2, "foo2", null]'); +ERROR: variable "j1" already created as TRANSACTIONAL +SELECT pgv_set_jsonb('vars2', 'j2', '{"bar": "baz2", "balance": 7.77, "active": true}', true); +ERROR: variable "j2" already created as NOT TRANSACTIONAL +SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str66' :: varchar)); +ERROR: variable "r1" already created as TRANSACTIONAL +SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str66' :: varchar),true); +ERROR: variable "r2" already created as NOT TRANSACTIONAL +-- CHECK pgv_list() WHILE WE HAVE A LOT OF MISCELLANEOUS VARIABLES +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+---------+------------------ + vars | any1 | t + vars | any2 | f + vars | d1 | t + vars | d2 | f + vars | int1 | t + vars | int2 | f + vars | intNULL | t + vars | num1 | t + vars | num2 | f + vars | str1 | t + vars | str2 | f + vars | ts1 | t + vars | ts2 | f + vars | tstz1 | t + vars | tstz2 | f + vars2 | j1 | t + vars2 | j2 | f + vars3 | r1 | t + vars3 | r2 | f +(19 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- VARIABLES DECLARED IN SUBTRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK TO SAVEPOINT +-- For better readability we don't use deprecated api functions in test below +BEGIN; +SAVEPOINT sp_to_rollback; +SELECT pgv_set('vars', 'any1', 'text value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'text value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_insert('vars3', 'r1', row(6 :: integer, 'str44' :: varchar), true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(6 :: integer, 'str44' :: varchar)); + pgv_insert +------------ + +(1 row) + +ROLLBACK TO sp_to_rollback; +COMMIT; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized variable "any1" +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +------------ + text value +(1 row) + +SELECT pgv_select('vars3', 'r1'); +ERROR: unrecognized variable "r1" +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (6,str44) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION +BEGIN; +SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------------- + after savepoint sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------------- + before savepoint sp1 +(1 row) + +COMMIT; +BEGIN; +SAVEPOINT sp1; +SAVEPOINT sp2; +SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars2', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +ROLLBACK TO sp1; +COMMIT; +SELECT pgv_get('vars2', 'any1',NULL::text); +ERROR: unrecognized package "vars2" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--CHECK TRANSACTION COMMIT +-- Declare variables +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'some value'::text); + pgv_set +--------- + +(1 row) + +BEGIN; +-- Set new values +SELECT pgv_set('vars', 'any1', 'another value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'another value'::text); + pgv_set +--------- + +(1 row) + +-- Check values before committing transaction +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +-- Check values after committing transaction +COMMIT; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +SELECT pgv_insert('vars3', 'r2', tab) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +BEGIN; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'str55' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars3', 'r2', row(5 :: integer, 'str55' :: varchar)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +COMMIT; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +-- CHECK TRANSACTION ROLLBACK +-- Variables are already declared +BEGIN; +-- Set new values +SELECT pgv_set('vars', 'any1', 'one more value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'one more value'::text); + pgv_set +--------- + +(1 row) + +-- Check values before rollback +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +-- Check values after rollback +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------- + another value +(1 row) + +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +---------------- + one more value +(1 row) + +-- Record variables +BEGIN; +SELECT pgv_delete('vars3', 'r1', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_delete('vars3', 'r2', 5); + pgv_delete +------------ + t +(1 row) + +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +ROLLBACK; +SELECT pgv_select('vars3', 'r1'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (5,str55) + (0,str00) +(5 rows) + +SELECT pgv_select('vars3', 'r2'); + pgv_select +------------ + (,strNULL) + (1,str33) + (2,) + (0,str00) +(4 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- VARIABLES DECLARED IN TRANSACTION SHOULD BE DESTROYED AFTER ROLLBACK +BEGIN; +SELECT pgv_set('vars', 'any1', 'text value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'any2', 'text value'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_insert('vars', 'r1', row(6 :: integer, 'str44' :: varchar), true); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r2', row(6 :: integer, 'str44' :: varchar)); + pgv_insert +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized variable "any1" +SELECT pgv_get('vars', 'any2',NULL::text); + pgv_get +------------ + text value +(1 row) + +SELECT pgv_select('vars', 'r1'); +ERROR: unrecognized variable "r1" +SELECT pgv_select('vars', 'r2'); + pgv_select +------------ + (6,str44) +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +-- CHECK ROLLBACK AFTER COMMITTING SUBTRANSACTION +SELECT pgv_set('vars', 'any1', 'before transaction block'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'before savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'after savepoint sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'after savepoint sp2'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------------------- + after savepoint sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +---------------------- + before savepoint sp1 +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +-------------------------- + before transaction block +(1 row) + +BEGIN; +SAVEPOINT sp1; +SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +RELEASE sp1; +SELECT pgv_get('vars2', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +ROLLBACK; +SELECT pgv_get('vars2', 'any1',NULL::text); +ERROR: unrecognized package "vars2" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Additional tests +SELECT pgv_insert('vars3', 'r1', tab, true) FROM tab; + pgv_insert +------------ + + + + +(4 rows) + +BEGIN; +SELECT pgv_insert('vars3', 'r1', row(5 :: integer, 'before savepoint sp1' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_update('vars3', 'r1', row(5 :: integer, 'after savepoint sp1' :: varchar)); + pgv_update +------------ + t +(1 row) + +SAVEPOINT sp2; +SELECT pgv_insert('vars3', 'r1', row(7 :: integer, 'row after sp2 to remove in sp4' :: varchar),true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT sp3; +SAVEPOINT sp4; +SELECT pgv_delete('vars3', 'r1', 7); + pgv_delete +------------ + t +(1 row) + +SAVEPOINT sp5; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +ROLLBACK TO sp5; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +RELEASE sp4; +SELECT pgv_select('vars3', 'r1'); + pgv_select +--------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) +(5 rows) + +ROLLBACK TO sp3; +SELECT pgv_select('vars3', 'r1'); + pgv_select +-------------------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) + (7,"row after sp2 to remove in sp4") +(6 rows) + +RELEASE sp2; +SELECT pgv_select('vars3', 'r1'); + pgv_select +-------------------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"after savepoint sp1") + (0,str00) + (7,"row after sp2 to remove in sp4") +(6 rows) + +ROLLBACK TO sp1; +SELECT pgv_select('vars3', 'r1'); + pgv_select +---------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"before savepoint sp1") + (0,str00) +(5 rows) + +COMMIT; +SELECT pgv_select('vars3', 'r1'); + pgv_select +---------------------------- + (,strNULL) + (1,str33) + (2,) + (5,"before savepoint sp1") + (0,str00) +(5 rows) + +SELECT pgv_set('vars', 'any1', 'outer'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'begin'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SELECT pgv_set('vars', 'any1', 'sp1'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp2; +SELECT pgv_set('vars', 'any1', 'sp2'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp3; +SAVEPOINT sp4; +SELECT pgv_set('vars', 'any1', 'sp4'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp5; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +ROLLBACK TO sp5; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +RELEASE sp4; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp4 +(1 row) + +ROLLBACK TO sp3; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp2 +(1 row) + +RELEASE sp2; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + sp2 +(1 row) + +ROLLBACK TO sp1; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + begin +(1 row) + +ROLLBACK; +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +--------- + outer +(1 row) + +BEGIN; +SELECT pgv_set('vars', 'any1', 'wrong type'::varchar, true); +ERROR: variable "any1" requires "text" value +COMMIT; +-- THE REMOVAL OF THE VARIABLE MUST BE CANCELED ON ROLLBACK +SELECT pgv_set('vars', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +ROLLBACK; +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + t +(1 row) + +SELECT pgv_get('vars', 'any1',NULL::text); + pgv_get +----------------- + variable exists +(1 row) + +BEGIN; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +COMMIT; +SELECT pgv_exists('vars', 'any1'); + pgv_exists +------------ + f +(1 row) + +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized package "vars" +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ + vars3 | r1 | t +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ + vars3 | r1 | t +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +COMMIT; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'regular', 'regular variable exists'::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars', 'trans1', 'trans1 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_free(); -- Check sequential package removal in one subtransaction + pgv_free +---------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'trans2', 'trans2 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans2 | t +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +ROLLBACK; +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans1 | t +(1 row) + +BEGIN; +SAVEPOINT sp1; +SAVEPOINT sp2; +SAVEPOINT sp3; +SELECT pgv_set('vars2', 'trans2', 'trans2 variable exists'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp4; +SAVEPOINT sp5; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +RELEASE sp5; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +RELEASE sp4; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars + vars2 +(2 rows) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +BEGIN; +SELECT pgv_set('vars', 'trans1', 'package created'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +SELECT pgv_set('vars', 'trans1', 'package restored'::text, true); + pgv_set +--------- + +(1 row) + +SELECT * FROM pgv_list() ORDER BY package, name; + package | name | is_transactional +---------+--------+------------------ + vars | trans1 | t +(1 row) + +COMMIT; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +-- REMOVED TRANSACTIONAL VARIABLE SHOULD BE NOT ACCESSIBLE THROUGH LastVariable +SELECT pgv_insert('package', 'errs',row(n), true) +FROM generate_series(1,5) AS gs(n) WHERE 1.0/(n-3)<>0; +ERROR: division by zero +SELECT pgv_insert('package', 'errs',row(1), true); + pgv_insert +------------ + +(1 row) + +-- Variable should not exists in case when error occurs during creation +SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); +ERROR: could not identify a hash function for type unknown +SELECT pgv_select('vars4', 'r1', 0); +ERROR: unrecognized package "vars4" +-- If variable created and removed in same transaction level, +-- it should be totally removed and should not be present +-- in changes list and cache. +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT comm; +SELECT pgv_remove('vars', 'any1'); + pgv_remove +------------ + +(1 row) + +RELEASE comm; +SELECT pgv_get('vars', 'any1',NULL::text); +ERROR: unrecognized package "vars" +COMMIT; +-- Tests for PGPRO-2440 +SELECT pgv_insert('vars3', 'r3', row(1 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +BEGIN; +SELECT pgv_insert('vars3', 'r3', row(2 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +SAVEPOINT comm; +SELECT pgv_insert('vars3', 'r3', row(3 :: integer, NULL::varchar), true); + pgv_insert +------------ + +(1 row) + +COMMIT; +SELECT pgv_delete('vars3', 'r3', 3); + pgv_delete +------------ + t +(1 row) + +BEGIN; +SELECT pgv_set('vars1', 't1', ''::text); + pgv_set +--------- + +(1 row) + +SELECT pgv_set('vars2', 't2', ''::text, true); + pgv_set +--------- + +(1 row) + +SAVEPOINT sp1; +SAVEPOINT sp2; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ERROR; +ERROR: syntax error at or near "ERROR" +LINE 1: ERROR; + ^ +COMMIT; +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SAVEPOINT sp_to_rollback; +SELECT pgv_set('vars', 'any1', 'some value'::text, true); + pgv_set +--------- + +(1 row) + +ROLLBACK TO sp_to_rollback; +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +-- Package should exist after rollback if it contains regular variable +BEGIN; +SELECT pgv_set('vars', 'any1', 'some value'::text); + pgv_set +--------- + +(1 row) + +ROLLBACK; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars +(1 row) + +-- Package should not exist if it becomes empty in rolled back transaction +BEGIN; +SAVEPOINT comm2; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +ROLLBACK TO comm2; +SELECT pgv_exists('vars'); + pgv_exists +------------ + f +(1 row) + +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- + vars +(1 row) + +COMMIT; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +SELECT pgv_set('vars', 'any1', 'some value'::text); + pgv_set +--------- + +(1 row) + +BEGIN; +SELECT pgv_remove('vars'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT package FROM pgv_stats() ORDER BY package; + package +--------- +(0 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Variables should be insertable after pgv_remove (variable) +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +BEGIN; +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | x | t +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +-- Variables should be insertable after pgv_remove (package) +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | x | t +(1 row) + +BEGIN; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | y | t +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +-- Variables should be insertable after pgv_free +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +ROLLBACK; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | y | t +(1 row) + +BEGIN; +SELECT pgv_insert('test', 'z', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +SELECT pgv_insert('test', 'z', ROW (1::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) +(1 row) + +SELECT pgv_insert('test', 'z', ROW (2::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +COMMIT; +SELECT * FROM pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + test | z | t +(1 row) + +SELECT pgv_select('test', 'z'); + pgv_select +------------ + (1,3) + (2,4) +(2 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- Variables should be rollbackable if transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +--- +--- Variables should not be rollbackable if not transactional +--- +-- case 1 (remove var) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 2 (remove pack) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- case 3 (free) +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +BEGIN; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +-- clear all +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #1 (remove var) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "y" +ROLLBACK; +SELECT pgv_select('test', 'y'); +ERROR: unrecognized variable "y" +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #2 (remove pack) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursors test #3 (free) +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test'); +ERROR: function pgv_select(unknown) does not exist +LINE 1: SELECT pgv_select('test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #4 +--- +-- non transactional, remove var +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, remove pac +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- non transactional, free +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional, remove var +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test', 'y'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, remove pack +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +-- transactional, free +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'y'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'y'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Cursor test #5 +--- +-- non transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +ROLLBACK; +SELECT pgv_select('test', 'x'); +ERROR: unrecognized package "test" +-- transactional +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_remove('test'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +SELECT pgv_select('test', 'x'); + pgv_select +------------ + (1,2) +(1 row) + +--- +--- Cursor test #6 +--- +--SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); +--BEGIN; +--DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +--FETCH 1 in r1_cur; +--CLOSE r1_cur; +--SELECT pgv_remove('test', 'x'); +--COMMIT; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Tests for "leaked hash_seq_search scan for hash table" +--- +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (3::int, 4::int), FALSE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'x') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'x') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +SELECT pgv_insert('test', 'y', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'y', ROW (3::int, 4::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +SELECT pgv_select('test', 'y') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_select('test', 'y') LIMIT 2; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +SELECT pgv_select('test', 'y') LIMIT 3; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r2_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 1 in r3_cur; + pgv_select +------------ + (1,2) +(1 row) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 2 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 3 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +ROLLBACK; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +DECLARE r2_cur CURSOR FOR SELECT pgv_select('test', 'y'); +DECLARE r3_cur CURSOR FOR SELECT pgv_select('test', 'x'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +FETCH 2 in r2_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +FETCH 3 in r3_cur; + pgv_select +------------ + (1,2) + (2,3) + (3,4) +(3 rows) + +COMMIT; +--- +--- Some special cases +--- +-- take #1 +SELECT pgv_insert('test', 'z1', ROW (2::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z1'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +SELECT pgv_remove('test', 'z1'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: unrecognized variable "z1" +ROLLBACK; +SELECT pgv_select('test', 'z1'); + pgv_select +------------ + (2,2) +(1 row) + +-- take #2 +SELECT pgv_insert('test', 'z2', ROW (2::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z2'); +FETCH 1 in r1_cur; + pgv_select +------------ + (2,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'z2'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: cursor "r1_cur" does not exist +ROLLBACK; +SELECT pgv_select('test', 'z2'); +ERROR: unrecognized variable "z2" +SELECT pgv_insert('test', 'z2', ROW (1::int, 2::int), FALSE); + pgv_insert +------------ + +(1 row) + +-- take #3 +SELECT pgv_insert('test', 'z3', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +CLOSE r1_cur; +SELECT pgv_remove('test', 'z3'); + pgv_remove +------------ + +(1 row) + +FETCH 1 in r1_cur; +ERROR: cursor "r1_cur" does not exist +ROLLBACK; +SELECT pgv_select('test', 'z3'); + pgv_select +------------ + (1,2) +(1 row) + +--BEGIN; +--DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'z3'); +--FETCH 1 in r1_cur; +--SELECT pgv_remove('test', 'z3'); +--COMMIT; +--SELECT pgv_select('test', 'z3'); +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- take #4 +SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test', 'x', ROW (2::int, 3::int), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +SAVEPOINT sp1; +FETCH 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +BEGIN; +SAVEPOINT sp1; +SELECT pgv_select('test', 'x') LIMIT 1; + pgv_select +------------ + (1,2) +(1 row) + +ROLLBACK TO SAVEPOINT sp1; +COMMIT; +--- +--- Test cases for pgv_stats +--- +--- Amount of allocated memory may vary from version to version, as well as from +--- platform to platform. Moreover, postgres versions less than 90600 always +--- show zero allocated memory. So, it's much easier to check if allocated +--- memory size is multiple of 8k since we use ALLOCSET_DEFAULT_INITSIZE +--- (see memutils.h), insted of creating multiple outputs files. +--- +CREATE TEMP VIEW pgv_stats_view(pack, mem_mult) AS + SELECT package, allocated_memory % 8192 as allocated_multiple_8192 + FROM pgv_stats() + ORDER BY 1; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +FETCH 1 in r1_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +FETCH 1 in r2_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), TRUE); +ERROR: there is a record in the variable "y" with same key +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +FETCH 1 in r1_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +FETCH 1 in r2_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_insert('test1', 'x', ROW (2::float, 1::float), FALSE); +ERROR: variable "x" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +FETCH 1 in r1_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +FETCH 1 in r2_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +COMMIT; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +BEGIN; +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +FETCH 1 in r1_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +FETCH 1 in r2_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +ROLLBACK; +SELECT pgv_insert('test1', 'y', ROW (2::float, 1::float), FALSE); +ERROR: variable "y" already created as TRANSACTIONAL +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Some special cases +--- +-- 1 +BEGIN; +SAVEPOINT comm2; +SELECT pgv_insert('test', 'x1', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +FETCH 1 in r1_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +FETCH 1 in r2_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +COMMIT; +-- 2 +BEGIN; +SELECT pgv_insert('test', 'x2', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +SAVEPOINT comm2; +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +FETCH 1 in r1_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +FETCH 1 in r2_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +COMMIT; +-- 3 +BEGIN; +SELECT pgv_insert('test', 'x3', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +SAVEPOINT comm2; +FETCH 1 in r1_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +FETCH 1 in r2_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +COMMIT; +-- 4 +BEGIN; +SELECT pgv_insert('test', 'x4', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +FETCH 1 in r1_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +SAVEPOINT comm2; +FETCH 1 in r2_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +COMMIT; +-- 5 +BEGIN; +SELECT pgv_insert('test', 'x5', ROW (2::float, 1::float), TRUE); + pgv_insert +------------ + +(1 row) + +DECLARE r1_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +DECLARE r2_cur CURSOR FOR SELECT pack, mem_mult FROM pgv_stats_view; +FETCH 1 in r1_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +FETCH 1 in r2_cur; + pack | mem_mult +------+---------- + test | 0 +(1 row) + +SAVEPOINT comm2; +COMMIT; +DROP VIEW pgv_stats_view; +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +--- +--- Test case for issue #32 [PGPRO-4456] +--- +CREATE TEMP TABLE tab (id int, t varchar); +INSERT INTO tab VALUES (0, 'str00'); +SELECT pgv_insert('vars', 'r1', row(1, 'str1', 'str2')); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'a', tab) FROM tab; + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r1', tab) FROM tab; +ERROR: new record structure have 2 attributes, but variable "r1" structure have 3. +SELECT pgv_select('vars', 'r1'); + pgv_select +--------------- + (1,str1,str2) +(1 row) + +SELECT pgv_insert('vars', 'r2', row(1, 'str1'::varchar)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'b', tab) FROM tab; + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r2', tab) FROM tab; + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars', 'r2'); + pgv_select +------------ + (1,str1) + (0,str00) +(2 rows) + +SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- +-- Test case for issue #38 [PGPRO-4676] +-- +SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE); + pgv_insert +------------ + +(1 row) + diff --git a/pg_variables.c b/pg_variables.c index d76e01f..bcd0e21 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -1489,7 +1489,9 @@ getMemoryTotalSpace(MemoryContext context, int level, Size *totalspace) /* Examine the context itself */ memset(&totals, 0, sizeof(totals)); -#if PG_VERSION_NUM >= 110000 +#if PG_VERSION_NUM >= 140000 + (*context->methods->stats) (context, NULL, NULL, &totals, true); +#elif PG_VERSION_NUM >= 110000 (*context->methods->stats) (context, NULL, NULL, &totals); #else (*context->methods->stats) (context, level, false, &totals); @@ -1641,7 +1643,11 @@ ensurePackagesHashExists(void) packagesHash = hash_create("Packages hash", NUMPACKAGES, &ctl, - HASH_ELEM | HASH_CONTEXT); + HASH_ELEM | +# if PG_VERSION_NUM >= 140000 + HASH_STRINGS | +# endif + HASH_CONTEXT); } /* @@ -1668,7 +1674,11 @@ makePackHTAB(Package *package, bool is_trans) ctl.hcxt = *context; *htab = hash_create(hash_name, NUMVARIABLES, &ctl, - HASH_ELEM | HASH_CONTEXT); + HASH_ELEM | +# if PG_VERSION_NUM >= 140000 + HASH_STRINGS | +# endif + HASH_CONTEXT); } static void From a92036be3732d6acd37f062b3b5b41ca04569c2a Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Fri, 2 Jul 2021 16:51:25 +0300 Subject: [PATCH 20/46] Changes for Travis-CI build --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5882736..6f7474d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,7 @@ +os: linux + +dist: focal + language: c services: From dbc3c83cfc6e40cb1c7d2e81d075fd98427eadaa Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Fri, 2 Jul 2021 17:58:51 +0300 Subject: [PATCH 21/46] travis-ci.org -> travis-ci.com --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 01be495..294ed37 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # pg_variables - session variables with various types -[![Build Status](https://travis-ci.org/postgrespro/pg_variables.svg?branch=master)](https://travis-ci.org/postgrespro/pg_variables) +[![Build Status](https://travis-ci.com/postgrespro/pg_variables.svg?branch=master)](https://travis-ci.com/postgrespro/pg_variables) [![codecov](https://codecov.io/gh/postgrespro/pg_variables/branch/master/graph/badge.svg)](https://codecov.io/gh/postgrespro/pg_variables) [![GitHub license](https://img.shields.io/badge/license-PostgreSQL-blue.svg)](https://raw.githubusercontent.com/postgrespro/pg_variables/master/README.md) From 8652451e1ec81f6978da705af4e3a4cb6d691d67 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Thu, 4 Nov 2021 17:08:19 +0300 Subject: [PATCH 22/46] Changes for pg_variables and ATX compatibility --- Makefile | 2 +- expected/pg_variables_atx.out | 571 ++++++++++++++++++++++++++++++++ expected/pg_variables_atx_0.out | 465 ++++++++++++++++++++++++++ expected/pg_variables_atx_1.out | 465 ++++++++++++++++++++++++++ pg_variables.c | 385 +++++++++++++++++---- pg_variables.h | 25 +- sql/pg_variables_atx.sql | 196 +++++++++++ 7 files changed, 2047 insertions(+), 62 deletions(-) create mode 100644 expected/pg_variables_atx.out create mode 100644 expected/pg_variables_atx_0.out create mode 100644 expected/pg_variables_atx_1.out create mode 100644 sql/pg_variables_atx.sql diff --git a/Makefile b/Makefile index 7e262ff..f95c39f 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ DATA_built = $(EXTENSION)--$(EXTVERSION).sql PGFILEDESC = "pg_variables - sessional variables" -REGRESS = pg_variables pg_variables_any pg_variables_trans +REGRESS = pg_variables pg_variables_any pg_variables_trans pg_variables_atx ifdef USE_PGXS PG_CONFIG = pg_config diff --git a/expected/pg_variables_atx.out b/expected/pg_variables_atx.out new file mode 100644 index 0000000..3322c37 --- /dev/null +++ b/expected/pg_variables_atx.out @@ -0,0 +1,571 @@ +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------ +-- Non-transactional variables +------------------------------ +select pgv_set('vars', 'int1', 101); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102); + pgv_set +--------- + +(1 row) + + begin autonomous; + select pgv_set('vars', 'int3', 103); + pgv_set +--------- + +(1 row) + +-- 101, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 101 | 102 | 103 +(1 row) + + select pgv_set('vars', 'int1', 1001); + pgv_set +--------- + +(1 row) + + begin autonomous; +-- 1001, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 102 | 103 +(1 row) + + select pgv_set('vars', 'int2', 1002); + pgv_set +--------- + +(1 row) + + commit; + commit; +-- 1001, 1002, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 1002 | 103 +(1 row) + + select pgv_set('vars', 'int3', 1003); + pgv_set +--------- + +(1 row) + +rollback; +-- 1001, 1002, 1003: +select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 1002 | 1003 +(1 row) + +-- vars:int1, vars:int2, vars:int3: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | f + vars | int2 | f + vars | int3 | f +(3 rows) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +-------------------------- +-- Transactional variables +-------------------------- +select pgv_set('vars', 'int1', 101, true); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102, true); + pgv_set +--------- + +(1 row) + + begin autonomous; + select pgv_set('vars', 'int3', 103, true); + pgv_set +--------- + +(1 row) + +-- 103: + select pgv_get('vars', 'int3', null::int); + pgv_get +--------- + 103 +(1 row) + + begin autonomous; + select pgv_set('vars', 'int2', 1002, true); + pgv_set +--------- + +(1 row) + +-- 1002: + select pgv_get('vars', 'int2', null::int); + pgv_get +--------- + 1002 +(1 row) + + commit; +-- 103: + select pgv_get('vars', 'int3', null::int); + pgv_get +--------- + 103 +(1 row) + + commit; + select pgv_set('vars', 'int1', 1001, true); + pgv_set +--------- + +(1 row) + +-- 1001: + select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1001 +(1 row) + +-- 102: + select pgv_get('vars', 'int2', null::int); + pgv_get +--------- + 102 +(1 row) + +rollback; +-- 101: +select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 101 +(1 row) + +-- vars:int1: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | t +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +---------- +-- Cursors +---------- +select pgv_insert('test', 'x', row (1::int, 2::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (2::int, 3::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (3::int, 4::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (10::int, 20::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (20::int, 30::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (30::int, 40::int), true); + pgv_insert +------------ + +(1 row) + +begin; + declare r1_cur cursor for select pgv_select('test', 'x'); + begin autonomous; + begin autonomous; + begin autonomous; + begin autonomous; + begin autonomous; + select pgv_insert('test', 'z', row (11::int, 22::int), false); + pgv_insert +------------ + +(1 row) + + select pgv_insert('test', 'z', row (22::int, 33::int), false); + pgv_insert +------------ + +(1 row) + + select pgv_insert('test', 'z', row (33::int, 44::int), false); + pgv_insert +------------ + +(1 row) + + declare r11_cur cursor for select pgv_select('test', 'x'); +-- (1,2),(2,3): + fetch 2 in r11_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + + declare r2_cur cursor for select pgv_select('test', 'y'); +-- correct error: unrecognized variable "y" + fetch 2 in r2_cur; +ERROR: unrecognized variable "y" + rollback; + rollback; + rollback; + rollback; + rollback; + declare r2_cur cursor for select pgv_select('test', 'y'); + declare r3_cur cursor for select pgv_select('test', 'z'); +-- (1,2),(2,3): + fetch 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +-- (10,20),(20,30): + fetch 2 in r2_cur; + pgv_select +------------ + (10,20) + (20,30) +(2 rows) + +-- (11,22),(22,33): + fetch 2 in r3_cur; + pgv_select +------------ + (11,22) + (22,33) +(2 rows) + +rollback; +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------ +-- Savepoint: rollback in main transaction +------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 101, true); + pgv_set +--------- + +(1 row) + +-- 101: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 101 +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 102, true); + pgv_set +--------- + +(1 row) + +-- 102: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 102 +(1 row) + + begin autonomous; + select pgv_set('vars', 'trans_int', 103, true); + pgv_set +--------- + +(1 row) + +-- 103: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 103 +(1 row) + + commit; +-- 102: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 102 +(1 row) + + rollback to sp1; +commit; +-- 101: +select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 101 +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------ +-- Savepoint: rollback in autonomous transaction +------------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 1, true); + pgv_set +--------- + +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 100, true); + pgv_set +--------- + +(1 row) + + begin autonomous; + begin autonomous; + select pgv_set('vars1', 'int1', 2); + pgv_set +--------- + +(1 row) + + select pgv_set('vars1', 'trans_int1', 3, true); + pgv_set +--------- + +(1 row) + + savepoint sp2; + select pgv_set('vars1', 'trans_int1', 4, true); + pgv_set +--------- + +(1 row) + +-- 2 + select pgv_get('vars1', 'int1', null::int); + pgv_get +--------- + 2 +(1 row) + +-- 4 + select pgv_get('vars1', 'trans_int1', null::int); + pgv_get +--------- + 4 +(1 row) + + rollback to sp2; +-- 3 + select pgv_get('vars1', 'trans_int1', null::int); + pgv_get +--------- + 3 +(1 row) + +-- vars1:int1, vars1:trans_int1: + select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------------+------------------ + vars1 | int1 | f + vars1 | trans_int1 | t +(2 rows) + + select pgv_set('vars1', 'trans_int2', 4, true); + pgv_set +--------- + +(1 row) + + select pgv_set('vars1', 'trans_int3', 5, true); + pgv_set +--------- + +(1 row) + + select pgv_set('vars1', 'int2', 3); + pgv_set +--------- + +(1 row) + + rollback; + commit; + rollback to sp1; +-- 1 + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 1 +(1 row) + +-- 2 + select pgv_get('vars1', 'int1', null::int); + pgv_get +--------- + 2 +(1 row) + +-- 3 + select pgv_get('vars1', 'int2', null::int); + pgv_get +--------- + 3 +(1 row) + +-- vars:trans_int, vars1:int1, vars1:int2: + select * from pgv_list() order by package, name; + package | name | is_transactional +---------+-----------+------------------ + vars | trans_int | t + vars1 | int1 | f + vars1 | int2 | f +(3 rows) + +commit; +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------------------ +-- Sample with (subxact inside ATX) == (subxact outside ATX) +------------------------------------------------------------ +select pgv_set('vars1', 'int1', 0); + pgv_set +--------- + +(1 row) + +select pgv_set('vars1', 'trans_int1', 0, true); + pgv_set +--------- + +(1 row) + +begin; + begin autonomous; + select pgv_set('vars1', 'int1', 1); + pgv_set +--------- + +(1 row) + + select pgv_set('vars1', 'trans_int1', 2, true); + pgv_set +--------- + +(1 row) + + savepoint sp2; + select pgv_set('vars1', 'trans_int1', 3, true); + pgv_set +--------- + +(1 row) + + rollback to sp2; +-- 2 + select pgv_get('vars1', 'trans_int1', null::int); + pgv_get +--------- + 2 +(1 row) + + commit; +rollback; +-- vars1:int1, vars1:trans_int1 +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------------+------------------ + vars1 | int1 | f + vars1 | trans_int1 | t +(2 rows) + +-- 1 +select pgv_get('vars1', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + +-- 0 +select pgv_get('vars1', 'trans_int1', null::int); + pgv_get +--------- + 0 +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/expected/pg_variables_atx_0.out b/expected/pg_variables_atx_0.out new file mode 100644 index 0000000..3ffdc86 --- /dev/null +++ b/expected/pg_variables_atx_0.out @@ -0,0 +1,465 @@ +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------ +-- Non-transactional variables +------------------------------ +select pgv_set('vars', 'int1', 101); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102); + pgv_set +--------- + +(1 row) + + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars', 'int3', 103); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 101, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars', 'int1', 1001); +ERROR: current transaction is aborted, commands ignored until end of transaction block + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ +-- 1001, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars', 'int2', 1002); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; + commit; +WARNING: there is no transaction in progress +-- 1001, 1002, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); +ERROR: unrecognized variable "int3" + select pgv_set('vars', 'int3', 1003); + pgv_set +--------- + +(1 row) + +rollback; +WARNING: there is no transaction in progress +-- 1001, 1002, 1003: +select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 101 | 102 | 1003 +(1 row) + +-- vars:int1, vars:int2, vars:int3: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | f + vars | int2 | f + vars | int3 | f +(3 rows) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +-------------------------- +-- Transactional variables +-------------------------- +select pgv_set('vars', 'int1', 101, true); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102, true); + pgv_set +--------- + +(1 row) + + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars', 'int3', 103, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 103: + select pgv_get('vars', 'int3', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars', 'int2', 1002, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 1002: + select pgv_get('vars', 'int2', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +-- 103: + select pgv_get('vars', 'int3', null::int); +ERROR: unrecognized variable "int3" + commit; +WARNING: there is no transaction in progress + select pgv_set('vars', 'int1', 1001, true); + pgv_set +--------- + +(1 row) + +-- 1001: + select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1001 +(1 row) + +-- 102: + select pgv_get('vars', 'int2', null::int); +ERROR: unrecognized variable "int2" +rollback; +WARNING: there is no transaction in progress +-- 101: +select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1001 +(1 row) + +-- vars:int1: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | t +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +---------- +-- Cursors +---------- +select pgv_insert('test', 'x', row (1::int, 2::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (2::int, 3::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (3::int, 4::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (10::int, 20::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (20::int, 30::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (30::int, 40::int), true); + pgv_insert +------------ + +(1 row) + +begin; + declare r1_cur cursor for select pgv_select('test', 'x'); + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_insert('test', 'z', row (11::int, 22::int), false); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_insert('test', 'z', row (22::int, 33::int), false); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_insert('test', 'z', row (33::int, 44::int), false); +ERROR: current transaction is aborted, commands ignored until end of transaction block + declare r11_cur cursor for select pgv_select('test', 'x'); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- (1,2),(2,3): + fetch 2 in r11_cur; +ERROR: current transaction is aborted, commands ignored until end of transaction block + declare r2_cur cursor for select pgv_select('test', 'y'); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- correct error: unrecognized variable "y" + fetch 2 in r2_cur; +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback; + rollback; +WARNING: there is no transaction in progress + rollback; +WARNING: there is no transaction in progress + rollback; +WARNING: there is no transaction in progress + rollback; +WARNING: there is no transaction in progress + declare r2_cur cursor for select pgv_select('test', 'y'); +ERROR: DECLARE CURSOR can only be used in transaction blocks + declare r3_cur cursor for select pgv_select('test', 'z'); +ERROR: DECLARE CURSOR can only be used in transaction blocks +-- (1,2),(2,3): + fetch 2 in r1_cur; +ERROR: cursor "r1_cur" does not exist +-- (10,20),(20,30): + fetch 2 in r2_cur; +ERROR: cursor "r2_cur" does not exist +-- (11,22),(22,33): + fetch 2 in r3_cur; +ERROR: cursor "r3_cur" does not exist +rollback; +WARNING: there is no transaction in progress +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------ +-- Savepoint: rollback in main transaction +------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 101, true); + pgv_set +--------- + +(1 row) + +-- 101: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 101 +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 102, true); + pgv_set +--------- + +(1 row) + +-- 102: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 102 +(1 row) + + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars', 'trans_int', 103, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 103: + select pgv_get('vars', 'trans_int', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +-- 102: + select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" + rollback to sp1; +ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks +commit; +WARNING: there is no transaction in progress +-- 101: +select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------ +-- Savepoint: rollback in autonomous transaction +------------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 1, true); + pgv_set +--------- + +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 100, true); + pgv_set +--------- + +(1 row) + + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars1', 'int1', 2); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 3, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + savepoint sp2; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 4, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 2 + select pgv_get('vars1', 'int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 4 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback to sp2; +ERROR: savepoint "sp2" does not exist +-- 3 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- vars1:int1, vars1:trans_int1: + select * from pgv_list() order by package, name; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int2', 4, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int3', 5, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'int2', 3); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback; + commit; +WARNING: there is no transaction in progress + rollback to sp1; +ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks +-- 1 + select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" +-- 2 + select pgv_get('vars1', 'int1', null::int); +ERROR: unrecognized package "vars1" +-- 3 + select pgv_get('vars1', 'int2', null::int); +ERROR: unrecognized package "vars1" +-- vars:trans_int, vars1:int1, vars1:int2: + select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +commit; +WARNING: there is no transaction in progress +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------------------ +-- Sample with (subxact inside ATX) == (subxact outside ATX) +------------------------------------------------------------ +select pgv_set('vars1', 'int1', 0); + pgv_set +--------- + +(1 row) + +select pgv_set('vars1', 'trans_int1', 0, true); + pgv_set +--------- + +(1 row) + +begin; + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars1', 'int1', 1); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 2, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + savepoint sp2; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 3, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback to sp2; +ERROR: savepoint "sp2" does not exist +-- 2 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +rollback; +WARNING: there is no transaction in progress +-- vars1:int1, vars1:trans_int1 +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------------+------------------ + vars1 | int1 | f + vars1 | trans_int1 | t +(2 rows) + +-- 1 +select pgv_get('vars1', 'int1', null::int); + pgv_get +--------- + 0 +(1 row) + +-- 0 +select pgv_get('vars1', 'trans_int1', null::int); + pgv_get +--------- + 0 +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/expected/pg_variables_atx_1.out b/expected/pg_variables_atx_1.out new file mode 100644 index 0000000..b5d8a07 --- /dev/null +++ b/expected/pg_variables_atx_1.out @@ -0,0 +1,465 @@ +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------ +-- Non-transactional variables +------------------------------ +select pgv_set('vars', 'int1', 101); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102); + pgv_set +--------- + +(1 row) + + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars', 'int3', 103); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 101, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars', 'int1', 1001); +ERROR: current transaction is aborted, commands ignored until end of transaction block + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ +-- 1001, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars', 'int2', 1002); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; + commit; +WARNING: there is no transaction in progress +-- 1001, 1002, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); +ERROR: unrecognized variable "int3" + select pgv_set('vars', 'int3', 1003); + pgv_set +--------- + +(1 row) + +rollback; +WARNING: there is no transaction in progress +-- 1001, 1002, 1003: +select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 101 | 102 | 1003 +(1 row) + +-- vars:int1, vars:int2, vars:int3: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | f + vars | int2 | f + vars | int3 | f +(3 rows) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +-------------------------- +-- Transactional variables +-------------------------- +select pgv_set('vars', 'int1', 101, true); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102, true); + pgv_set +--------- + +(1 row) + + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars', 'int3', 103, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 103: + select pgv_get('vars', 'int3', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars', 'int2', 1002, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 1002: + select pgv_get('vars', 'int2', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +-- 103: + select pgv_get('vars', 'int3', null::int); +ERROR: unrecognized variable "int3" + commit; +WARNING: there is no transaction in progress + select pgv_set('vars', 'int1', 1001, true); + pgv_set +--------- + +(1 row) + +-- 1001: + select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1001 +(1 row) + +-- 102: + select pgv_get('vars', 'int2', null::int); +ERROR: unrecognized variable "int2" +rollback; +WARNING: there is no transaction in progress +-- 101: +select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1001 +(1 row) + +-- vars:int1: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | t +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +---------- +-- Cursors +---------- +select pgv_insert('test', 'x', row (1::int, 2::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (2::int, 3::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (3::int, 4::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (10::int, 20::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (20::int, 30::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (30::int, 40::int), true); + pgv_insert +------------ + +(1 row) + +begin; + declare r1_cur cursor for select pgv_select('test', 'x'); + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_insert('test', 'z', row (11::int, 22::int), false); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_insert('test', 'z', row (22::int, 33::int), false); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_insert('test', 'z', row (33::int, 44::int), false); +ERROR: current transaction is aborted, commands ignored until end of transaction block + declare r11_cur cursor for select pgv_select('test', 'x'); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- (1,2),(2,3): + fetch 2 in r11_cur; +ERROR: current transaction is aborted, commands ignored until end of transaction block + declare r2_cur cursor for select pgv_select('test', 'y'); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- correct error: unrecognized variable "y" + fetch 2 in r2_cur; +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback; + rollback; +WARNING: there is no transaction in progress + rollback; +WARNING: there is no transaction in progress + rollback; +WARNING: there is no transaction in progress + rollback; +WARNING: there is no transaction in progress + declare r2_cur cursor for select pgv_select('test', 'y'); +ERROR: DECLARE CURSOR can only be used in transaction blocks + declare r3_cur cursor for select pgv_select('test', 'z'); +ERROR: DECLARE CURSOR can only be used in transaction blocks +-- (1,2),(2,3): + fetch 2 in r1_cur; +ERROR: cursor "r1_cur" does not exist +-- (10,20),(20,30): + fetch 2 in r2_cur; +ERROR: cursor "r2_cur" does not exist +-- (11,22),(22,33): + fetch 2 in r3_cur; +ERROR: cursor "r3_cur" does not exist +rollback; +WARNING: there is no transaction in progress +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------ +-- Savepoint: rollback in main transaction +------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 101, true); + pgv_set +--------- + +(1 row) + +-- 101: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 101 +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 102, true); + pgv_set +--------- + +(1 row) + +-- 102: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 102 +(1 row) + + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars', 'trans_int', 103, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 103: + select pgv_get('vars', 'trans_int', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +-- 102: + select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" + rollback to sp1; +ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks +commit; +WARNING: there is no transaction in progress +-- 101: +select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------ +-- Savepoint: rollback in autonomous transaction +------------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 1, true); + pgv_set +--------- + +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 100, true); + pgv_set +--------- + +(1 row) + + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars1', 'int1', 2); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 3, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + savepoint sp2; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 4, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 2 + select pgv_get('vars1', 'int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 4 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback to sp2; +ERROR: no such savepoint +-- 3 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- vars1:int1, vars1:trans_int1: + select * from pgv_list() order by package, name; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int2', 4, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int3', 5, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'int2', 3); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback; + commit; +WARNING: there is no transaction in progress + rollback to sp1; +ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks +-- 1 + select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" +-- 2 + select pgv_get('vars1', 'int1', null::int); +ERROR: unrecognized package "vars1" +-- 3 + select pgv_get('vars1', 'int2', null::int); +ERROR: unrecognized package "vars1" +-- vars:trans_int, vars1:int1, vars1:int2: + select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +commit; +WARNING: there is no transaction in progress +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------------------ +-- Sample with (subxact inside ATX) == (subxact outside ATX) +------------------------------------------------------------ +select pgv_set('vars1', 'int1', 0); + pgv_set +--------- + +(1 row) + +select pgv_set('vars1', 'trans_int1', 0, true); + pgv_set +--------- + +(1 row) + +begin; + begin autonomous; +ERROR: syntax error at or near "autonomous" +LINE 1: begin autonomous; + ^ + select pgv_set('vars1', 'int1', 1); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 2, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + savepoint sp2; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 3, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback to sp2; +ERROR: no such savepoint +-- 2 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +rollback; +WARNING: there is no transaction in progress +-- vars1:int1, vars1:trans_int1 +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------------+------------------ + vars1 | int1 | f + vars1 | trans_int1 | t +(2 rows) + +-- 1 +select pgv_get('vars1', 'int1', null::int); + pgv_get +--------- + 0 +(1 row) + +-- 0 +select pgv_get('vars1', 'trans_int1', null::int); + pgv_get +--------- + 0 +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/pg_variables.c b/pg_variables.c index bcd0e21..9730101 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -3,7 +3,7 @@ * pg_variables.c * Functions, which get or set variables values * - * Copyright (c) 2015-2016, Postgres Professional + * Copyright (c) 2015-2021, Postgres Professional * *------------------------------------------------------------------------- */ @@ -79,6 +79,11 @@ static void pushChangesStack(void); static int numOfRegVars(Package *package); +#ifdef PGPRO_EE +static void pgvSaveContext(void); +static void pgvRestoreContext(void); +#endif + /* Constructors */ static void makePackHTAB(Package *package, bool is_trans); static inline ChangedObject *makeChangedObject(TransObject *object, @@ -153,15 +158,31 @@ typedef struct tagVariableStatEntry HASH_SEQ_STATUS *status; Variable *variable; Package *package; - int level; + Levels levels; } VariableStatEntry; typedef struct tagPackageStatEntry { HASH_SEQ_STATUS *status; - int level; + Levels levels; } PackageStatEntry; +#ifdef PGPRO_EE +/* + * Context for storing/restoring parameters when switching autonomous + * transactions + */ +typedef struct PgvContextStruct +{ + dlist_head *changesStack; + MemoryContext changesStackContext; + struct PgvContextStruct *next; +} PgvContextStruct; + +static PgvContextStruct *pgv_context = NULL; + +#endif /* PGPRO_EE */ + /* * Compare functions for VariableStatEntry and PackageStatEntry members. */ @@ -192,7 +213,12 @@ VariableStatEntry_eq_all(void *entry, void *value) static bool VariableStatEntry_level_eq(void *entry, void *value) { - return ((VariableStatEntry *) entry)->level == *(int *) value; + return +#ifdef PGPRO_EE + /* Compare ATX level */ + ((VariableStatEntry *) entry)->levels.atxlevel == ((Levels *) value)->atxlevel && +#endif + ((VariableStatEntry *) entry)->levels.level == ((Levels *) value)->level; } static bool @@ -204,9 +230,22 @@ PackageStatEntry_status_eq(void *entry, void *value) static bool PackageStatEntry_level_eq(void *entry, void *value) { - return ((PackageStatEntry *) entry)->level == *(int *) value; + return +#ifdef PGPRO_EE + /* Compare ATX level */ + ((PackageStatEntry *) entry)->levels.atxlevel == ((Levels *) value)->atxlevel && +#endif + ((PackageStatEntry *) entry)->levels.level == ((Levels *) value)->level; } +#ifdef PGPRO_EE +static bool +VariableStatEntry_is_transactional(void *entry, void *value) +{ + return ((VariableStatEntry *) entry)->variable->is_transactional; +} +#endif + /* * VariableStatEntry and PackageStatEntry status member getters. */ @@ -367,12 +406,12 @@ remove_variables_package(List **list, Package *package) * Remove all the entries for level. */ static void -remove_variables_level(List **list, int level) +remove_variables_level(List **list, Levels *levels) { RemoveIfContext ctx = { .list = list, - .value = &level, + .value = levels, .eq = VariableStatEntry_level_eq, .getter = VariableStatEntry_status_ptr, .match_first = false, @@ -421,12 +460,12 @@ remove_packages_status(List **list, HASH_SEQ_STATUS *status) * Remove all the entries with level for packages list. */ static void -remove_packages_level(List **list, int level) +remove_packages_level(List **list, Levels *levels) { RemoveIfContext ctx = { .list = list, - .value = &level, + .value = levels, .eq = PackageStatEntry_level_eq, .getter = PackageStatEntry_status_ptr, .match_first = false, @@ -435,6 +474,26 @@ remove_packages_level(List **list, int level) list_remove_if(ctx); } +#ifdef PGPRO_EE +/* + * Remove all transactional entries. + */ +static void +remove_variables_transactional(List **list) +{ + RemoveIfContext ctx = + { + .list = list, + .value = NULL, + .eq = VariableStatEntry_is_transactional, + .getter = VariableStatEntry_status_ptr, + .match_first = false, + .term = true + }; + list_remove_if(ctx); +} +#endif + static void freeStatsLists(void); /* Returns a lists of packages and variables changed at current subxact level */ #define get_actual_changes_list() \ @@ -922,7 +981,10 @@ variable_select(PG_FUNCTION_ARGS) entry->status = rstat; entry->variable = variable; entry->package = package; - entry->level = GetCurrentTransactionNestLevel(); + entry->levels.level = GetCurrentTransactionNestLevel(); +#ifdef PGPRO_EE + entry->levels.atxlevel = getNestLevelATX(); +#endif variables_stats = lcons((void *)entry, variables_stats); MemoryContextSwitchTo(oldcontext); @@ -1552,7 +1614,10 @@ get_packages_stats(PG_FUNCTION_ARGS) funcctx->user_fctx = rstat; entry = palloc0(sizeof(PackageStatEntry)); entry->status = rstat; - entry->level = GetCurrentTransactionNestLevel(); + entry->levels.level = GetCurrentTransactionNestLevel(); +#ifdef PGPRO_EE + entry->levels.atxlevel = getNestLevelATX(); +#endif packages_stats = lcons((void *)entry, packages_stats); MemoryContextSwitchTo(ctx); } @@ -1643,7 +1708,7 @@ ensurePackagesHashExists(void) packagesHash = hash_create("Packages hash", NUMPACKAGES, &ctl, - HASH_ELEM | + HASH_ELEM | # if PG_VERSION_NUM >= 140000 HASH_STRINGS | # endif @@ -1794,6 +1859,9 @@ createPackage(text *name, bool is_trans) package->varHashTransact = NULL; package->hctxRegular = NULL; package->hctxTransact = NULL; +#ifdef PGPRO_EE + package->context = NULL; +#endif initObjectHistory(&package->transObject, TRANS_PACKAGE); } @@ -2045,6 +2113,10 @@ removeObject(TransObject *object, TransObjectType type) if (type == TRANS_PACKAGE) { +#ifdef PGPRO_EE + PackageContext *context, *next; +#endif + package = (Package *) object; /* Regular variables had already removed */ @@ -2052,6 +2124,19 @@ removeObject(TransObject *object, TransObjectType type) MemoryContextDelete(package->hctxRegular); if (package->hctxTransact) MemoryContextDelete(package->hctxTransact); +#ifdef PGPRO_EE + /* + * Remove contexts with transactional part (stored when switching to + * ATX transaction) + */ + context = package->context; + while (context) + { + next = context->next; + pfree(context); + context = next; + } +#endif hash = packagesHash; } else @@ -2146,7 +2231,10 @@ rollbackSavepoint(TransObject *object, TransObjectType type) { /* ...create a new state to make package valid. */ initObjectHistory(object, type); - GetActualState(object)->level = GetCurrentTransactionNestLevel() - 1; +#ifdef PGPRO_EE + GetActualState(object)->levels.atxlevel = getNestLevelATX(); +#endif + GetActualState(object)->levels.level = GetCurrentTransactionNestLevel() - 1; if (!dlist_is_empty(changesStack)) addToChangesStackUpperLevel(object, type); } @@ -2170,7 +2258,10 @@ rollbackSavepoint(TransObject *object, TransObjectType type) { createSavepoint(object, type); addToChangesStackUpperLevel(object, type); - GetActualState(object)->level = GetCurrentTransactionNestLevel() - 1; +#ifdef PGPRO_EE + GetActualState(object)->levels.atxlevel = getNestLevelATX(); +#endif + GetActualState(object)->levels.level = GetCurrentTransactionNestLevel() - 1; } GetActualState(object)->is_valid = false; } @@ -2190,7 +2281,7 @@ static void releaseSavepoint(TransObject *object, TransObjectType type) { dlist_head *states = &object->states; - Assert(GetActualState(object)->level == GetCurrentTransactionNestLevel()); + Assert(GetActualState(object)->levels.level == GetCurrentTransactionNestLevel()); /* * If the object is not valid and does not exist at a higher level @@ -2221,7 +2312,7 @@ releaseSavepoint(TransObject *object, TransObjectType type) addToChangesStackUpperLevel(object, type); /* Change subxact level due to release */ - GetActualState(object)->level--; + GetActualState(object)->levels.level--; } static void @@ -2252,7 +2343,15 @@ isObjectChangedInCurrentTrans(TransObject *object) return false; state = GetActualState(object); - return state->level == GetCurrentTransactionNestLevel(); + return +#ifdef PGPRO_EE + /* + * We should separate states with equal subxacts but with + * different ATX level + */ + state->levels.atxlevel == getNestLevelATX() && +#endif + state->levels.level == GetCurrentTransactionNestLevel(); } /* @@ -2266,13 +2365,32 @@ isObjectChangedInUpperTrans(TransObject *object) cur_state = GetActualState(object); if (dlist_has_next(&object->states, &cur_state->node) && - cur_state->level == GetCurrentTransactionNestLevel()) +#ifdef PGPRO_EE + cur_state->levels.atxlevel == getNestLevelATX() && +#endif + cur_state->levels.level == GetCurrentTransactionNestLevel()) { prev_state = dlist_container(TransState, node, cur_state->node.next); - return prev_state->level == GetCurrentTransactionNestLevel() - 1; + return +#ifdef PGPRO_EE + /* + * We should separate states with equal subxacts but with + * different ATX level + */ + prev_state->levels.atxlevel == getNestLevelATX() && +#endif + prev_state->levels.level == GetCurrentTransactionNestLevel() - 1; } else - return cur_state->level == GetCurrentTransactionNestLevel() - 1; + return +#ifdef PGPRO_EE + /* + * We should separate states with equal subxacts but with + * different ATX level + */ + cur_state->levels.atxlevel == getNestLevelATX() && +#endif + cur_state->levels.level == GetCurrentTransactionNestLevel() - 1; } /* @@ -2367,7 +2485,10 @@ addToChangesStack(TransObject *object, TransObjectType type) csn->changedVarsList, &co->node); /* Give this object current subxact level */ - GetActualState(object)->level = GetCurrentTransactionNestLevel(); + GetActualState(object)->levels.level = GetCurrentTransactionNestLevel(); +#ifdef PGPRO_EE + GetActualState(object)->levels.atxlevel = getNestLevelATX(); +#endif } } @@ -2466,54 +2587,176 @@ static void compatibility_check(void) { /* - * | Edition | ConnPool | ATX | COMPAT_CHECK | - * ------------------------------------------- - * | std 9.6 | no | no | no | - * | std 10 | no | no | yes | - * | std 11 | no | no | yes | - * | std 12 | no | no | yes | - * | std 13 | no | no | yes | - * | ee 9.6 | no | yes | no | - * | ee 10 | no | yes | yes | - * | ee 11 | yes | yes | yes | - * | ee 12 | yes | yes | yes | - * | ee 13 | yes | yes | yes | + * | Edition | ConnPool | + * ---------------------- + * | std 9.6 | no | + * | std 10 | no | + * | std 11 | no | + * | std 12 | no | + * | std 13 | no | + * | ee 9.6 | no | + * | ee 10 | no | + * | ee 11 | yes | + * | ee 12 | yes | + * | ee 13 | yes | */ +#if defined(PGPRO_EE) && PG_VERSION_NUM >= 110000 + if (!IsDedicatedBackend) + { + freeStatsLists(); + elog(ERROR, "pg_variables extension is incompatible with connection pooling"); + } +#endif /* PGPRO_EE */ +} + #ifdef PGPRO_EE +/* + * At the beginning of ATX store the pg_variables's env into + * pgv_context. + */ +static void +pgvSaveContext(void) +{ + Package *package; + HASH_SEQ_STATUS pstat; + PgvContextStruct *sus = MemoryContextAlloc(CurTransactionContext, + sizeof(PgvContextStruct)); -# if (PG_VERSION_NUM < 100000) - /* - * This versions does not have dedicated macro to check compatibility. - * So, use simple check here for ATX. - */ - if (getNestLevelATX() != 0) + /* Save transactional variables for all packages (in packages structs) */ + if (packagesHash != NULL) + { + /* Get packages list */ + hash_seq_init(&pstat, packagesHash); + while ((package = (Package *) hash_seq_search(&pstat)) != NULL) { - freeStatsLists(); - elog(ERROR, "pg_variables extension is not compatible with " - "autonomous transactions"); + PackageContext *context = MemoryContextAlloc(ModuleContext, + sizeof(PackageContext)); + context->next = package->context; + package->context = context; + + /* Save transactional variables in context */ + context->hctxTransact = package->hctxTransact; + context->varHashTransact = package->varHashTransact; + /* + * Package structure has a transactional part 'transObject'. + * This part is used in asserts like + * Assert(GetActualState(object)->levels.level == + * GetCurrentTransactionNestLevel()) + * But this comparison is not valid for ATX transactions because + * 'CurrentTransactionState->nestingLevel' for each of new ATX + * level is starts with 1. We should save package state at start + * of ATX transaction and restore it at finish. + * No need do this for transactional variables (we clean them at + * end of ATX transaction) and regular variables (we modify them + * directly). + */ + context->state = GetActualState(&package->transObject); + + package->hctxTransact = NULL; + package->varHashTransact = NULL; } -# else - /* - * Since ee10 there is PG_COMPATIBILITY_CHECK macro to check compatibility. - * But for some reasons it may not be present at the moment. - * So, if PG_COMPATIBILITY_CHECK macro is not present pg_variables are - * always compatible. - */ -# ifdef PG_COMPATIBILITY_CHECK + } + + /* Remove stats for all transactional variables */ + remove_variables_transactional(&variables_stats); + resetVariablesCache(); + + sus->changesStack = changesStack; + changesStack = NULL; + sus->changesStackContext = changesStackContext; + changesStackContext = NULL; + + sus->next = pgv_context; + pgv_context = sus; +} + +/* + * Restore pg_variables's env pointer from pgv_context. + */ +static void +pgvRestoreContext() +{ + Package *package; + HASH_SEQ_STATUS pstat; + PgvContextStruct *sus = pgv_context; + + resetVariablesCache(); + /* Delete changes stack for all transactional variables */ + if (changesStackContext) + { + MemoryContextDelete(changesStackContext); + changesStack = NULL; + changesStackContext = NULL; + } + /* We just finished ATX => need to free all hash_seq_search scans */ + freeStatsLists(); + + /* Restore transactional variables for all packages */ + if (packagesHash != NULL) + { + /* Get packages list */ + hash_seq_init(&pstat, packagesHash); + while ((package = (Package *) hash_seq_search(&pstat)) != NULL) { - if (!pg_compatibility_check_no_error()) - freeStatsLists(); + /* + * Delete context with transactional variables (they are + * no need outside ATX transaction) + */ + if (package->hctxTransact) + MemoryContextDelete(package->hctxTransact); + + /* We have stored context for this package? */ + if (package->context) + { + PackageContext *context = package->context; + PackageContext *next = context->next; + TransObject *object = &package->transObject; + TransState *state; + + /* Restore transactional variables from context */ + package->hctxTransact = context->hctxTransact; + package->varHashTransact = context->varHashTransact; - PG_COMPATIBILITY_CHECK(pg_variables); + /* Remove all package states, generated in ATX transaction */ + while ((state = GetActualState(object)) != context->state) + { + if (dlist_is_empty(&object->states)) + elog(ERROR, "pg_variables extension can not find " + "transaction state for package"); + removeState(object, TRANS_PACKAGE, state); + } + + pfree(context); + package->context = next; + } + else + { + /* Package was created in this autonomous transaction */ + package->hctxTransact = NULL; + package->varHashTransact = NULL; + /* + * No need to remove package states: for just created package + * we have one state with level = 0 + */ + } } -# endif /* PG_COMPATIBILITY_CHECK */ -# endif /* PG_VERSION_NUM */ + } -# undef ATX_CHECK -# undef CONNPOOL_CHECK + /* + * 'sus' can be NULL in case pg_variables was not initialized + * at start of transaction + */ + if (sus) + { + /* Restore changes stack for previous level: */ + changesStack = sus->changesStack; + changesStackContext = sus->changesStackContext; -#endif /* PGPRO_EE */ + pgv_context = sus->next; + pfree(sus); + } } +#endif /* PGPRO_EE */ /* * Intercept execution during subtransaction processing @@ -2522,6 +2765,8 @@ static void pgvSubTransCallback(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg) { + Levels levels; + if (changesStack) { switch (event) @@ -2541,8 +2786,12 @@ pgvSubTransCallback(SubXactEvent event, SubTransactionId mySubid, } } - remove_variables_level(&variables_stats, GetCurrentTransactionNestLevel()); - remove_packages_level(&packages_stats, GetCurrentTransactionNestLevel()); + levels.level = GetCurrentTransactionNestLevel(); +#ifdef PGPRO_EE + levels.atxlevel = getNestLevelATX(); +#endif + remove_variables_level(&variables_stats, &levels); + remove_packages_level(&packages_stats, &levels); } /* @@ -2575,6 +2824,22 @@ pgvTransCallback(XactEvent event, void *arg) if (event == XACT_EVENT_PRE_COMMIT || event == XACT_EVENT_ABORT) freeStatsLists(); + +#ifdef PGPRO_EE + if (getNestLevelATX() > 0) + { + if (event == XACT_EVENT_START) + { /* on each ATX transaction start */ + pgvSaveContext(); + } + else if (event == XACT_EVENT_ABORT || event == XACT_EVENT_PARALLEL_ABORT || + event == XACT_EVENT_COMMIT || event == XACT_EVENT_PARALLEL_COMMIT || + event == XACT_EVENT_PREPARE) + { /* on each ATX transaction finish */ + pgvRestoreContext(); + } + } +#endif } /* diff --git a/pg_variables.h b/pg_variables.h index b08faa6..864a5e2 100644 --- a/pg_variables.h +++ b/pg_variables.h @@ -52,12 +52,21 @@ typedef struct ScalarVar int16 typlen; } ScalarVar; +/* Object levels (subxact + atx) */ +typedef struct Levels +{ + int level; +#ifdef PGPRO_EE + int atxlevel; +#endif +} Levels; + /* State of TransObject instance */ typedef struct TransState { dlist_node node; bool is_valid; - int level; + Levels levels; } TransState; /* List node that stores one of the package's states */ @@ -85,6 +94,17 @@ typedef struct TransObject dlist_head states; } TransObject; +#ifdef PGPRO_EE +/* Package context for save transactional part of package */ +typedef struct PackageContext +{ + HTAB *varHashTransact; + MemoryContext hctxTransact; + TransState *state; + struct PackageContext *next; +} PackageContext; +#endif + /* Transactional package */ typedef struct Package { @@ -94,6 +114,9 @@ typedef struct Package /* Memory context for package variables for easy memory release */ MemoryContext hctxRegular, hctxTransact; +#ifdef PGPRO_EE + PackageContext *context; +#endif } Package; /* Transactional variable */ diff --git a/sql/pg_variables_atx.sql b/sql/pg_variables_atx.sql new file mode 100644 index 0000000..396ea18 --- /dev/null +++ b/sql/pg_variables_atx.sql @@ -0,0 +1,196 @@ +select pgv_free(); + +------------------------------ +-- Non-transactional variables +------------------------------ +select pgv_set('vars', 'int1', 101); +begin; + select pgv_set('vars', 'int2', 102); + begin autonomous; + select pgv_set('vars', 'int3', 103); +-- 101, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + select pgv_set('vars', 'int1', 1001); + begin autonomous; +-- 1001, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + select pgv_set('vars', 'int2', 1002); + commit; + commit; +-- 1001, 1002, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + select pgv_set('vars', 'int3', 1003); +rollback; + +-- 1001, 1002, 1003: +select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); +-- vars:int1, vars:int2, vars:int3: +select * from pgv_list() order by package, name; + +select pgv_free(); + +-------------------------- +-- Transactional variables +-------------------------- +select pgv_set('vars', 'int1', 101, true); +begin; + select pgv_set('vars', 'int2', 102, true); + begin autonomous; + select pgv_set('vars', 'int3', 103, true); +-- 103: + select pgv_get('vars', 'int3', null::int); + begin autonomous; + select pgv_set('vars', 'int2', 1002, true); +-- 1002: + select pgv_get('vars', 'int2', null::int); + commit; +-- 103: + select pgv_get('vars', 'int3', null::int); + commit; + select pgv_set('vars', 'int1', 1001, true); +-- 1001: + select pgv_get('vars', 'int1', null::int); +-- 102: + select pgv_get('vars', 'int2', null::int); +rollback; +-- 101: +select pgv_get('vars', 'int1', null::int); +-- vars:int1: +select * from pgv_list() order by package, name; + +select pgv_free(); + +---------- +-- Cursors +---------- +select pgv_insert('test', 'x', row (1::int, 2::int), false); +select pgv_insert('test', 'x', row (2::int, 3::int), false); +select pgv_insert('test', 'x', row (3::int, 4::int), false); + +select pgv_insert('test', 'y', row (10::int, 20::int), true); +select pgv_insert('test', 'y', row (20::int, 30::int), true); +select pgv_insert('test', 'y', row (30::int, 40::int), true); + +begin; + declare r1_cur cursor for select pgv_select('test', 'x'); + begin autonomous; + begin autonomous; + begin autonomous; + begin autonomous; + begin autonomous; + select pgv_insert('test', 'z', row (11::int, 22::int), false); + select pgv_insert('test', 'z', row (22::int, 33::int), false); + select pgv_insert('test', 'z', row (33::int, 44::int), false); + + declare r11_cur cursor for select pgv_select('test', 'x'); +-- (1,2),(2,3): + fetch 2 in r11_cur; + declare r2_cur cursor for select pgv_select('test', 'y'); +-- correct error: unrecognized variable "y" + fetch 2 in r2_cur; + rollback; + rollback; + rollback; + rollback; + rollback; + declare r2_cur cursor for select pgv_select('test', 'y'); + declare r3_cur cursor for select pgv_select('test', 'z'); +-- (1,2),(2,3): + fetch 2 in r1_cur; +-- (10,20),(20,30): + fetch 2 in r2_cur; +-- (11,22),(22,33): + fetch 2 in r3_cur; +rollback; + +select pgv_free(); + +------------------------------------------ +-- Savepoint: rollback in main transaction +------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 101, true); +-- 101: + select pgv_get('vars', 'trans_int', null::int); + savepoint sp1; + select pgv_set('vars', 'trans_int', 102, true); +-- 102: + select pgv_get('vars', 'trans_int', null::int); + begin autonomous; + select pgv_set('vars', 'trans_int', 103, true); +-- 103: + select pgv_get('vars', 'trans_int', null::int); + commit; +-- 102: + select pgv_get('vars', 'trans_int', null::int); + rollback to sp1; +commit; +-- 101: +select pgv_get('vars', 'trans_int', null::int); + +select pgv_free(); + +------------------------------------------------ +-- Savepoint: rollback in autonomous transaction +------------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 1, true); + savepoint sp1; + select pgv_set('vars', 'trans_int', 100, true); + begin autonomous; + begin autonomous; + select pgv_set('vars1', 'int1', 2); + select pgv_set('vars1', 'trans_int1', 3, true); + savepoint sp2; + select pgv_set('vars1', 'trans_int1', 4, true); +-- 2 + select pgv_get('vars1', 'int1', null::int); +-- 4 + select pgv_get('vars1', 'trans_int1', null::int); + rollback to sp2; +-- 3 + select pgv_get('vars1', 'trans_int1', null::int); +-- vars1:int1, vars1:trans_int1: + select * from pgv_list() order by package, name; + select pgv_set('vars1', 'trans_int2', 4, true); + select pgv_set('vars1', 'trans_int3', 5, true); + select pgv_set('vars1', 'int2', 3); + rollback; + commit; + rollback to sp1; +-- 1 + select pgv_get('vars', 'trans_int', null::int); +-- 2 + select pgv_get('vars1', 'int1', null::int); +-- 3 + select pgv_get('vars1', 'int2', null::int); +-- vars:trans_int, vars1:int1, vars1:int2: + select * from pgv_list() order by package, name; +commit; + +select pgv_free(); + +------------------------------------------------------------ +-- Sample with (subxact inside ATX) == (subxact outside ATX) +------------------------------------------------------------ +select pgv_set('vars1', 'int1', 0); +select pgv_set('vars1', 'trans_int1', 0, true); +begin; + begin autonomous; + select pgv_set('vars1', 'int1', 1); + select pgv_set('vars1', 'trans_int1', 2, true); + savepoint sp2; + select pgv_set('vars1', 'trans_int1', 3, true); + rollback to sp2; +-- 2 + select pgv_get('vars1', 'trans_int1', null::int); + commit; +rollback; +-- vars1:int1, vars1:trans_int1 +select * from pgv_list() order by package, name; +-- 1 +select pgv_get('vars1', 'int1', null::int); +-- 0 +select pgv_get('vars1', 'trans_int1', null::int); + +select pgv_free(); From 76019de1360ebdf3c41da3b8210f4fe5bae45199 Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Mon, 15 Nov 2021 17:33:14 +0300 Subject: [PATCH 23/46] Run pgindent --- pg_variables.c | 465 ++++++++++++++++++++++-------------------- pg_variables.h | 23 ++- pg_variables_record.c | 18 +- 3 files changed, 270 insertions(+), 236 deletions(-) diff --git a/pg_variables.c b/pg_variables.c index 9730101..46c7f24 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -77,7 +77,7 @@ static void addToChangesStackUpperLevel(TransObject *object, TransObjectType type); static void pushChangesStack(void); -static int numOfRegVars(Package *package); +static int numOfRegVars(Package *package); #ifdef PGPRO_EE static void pgvSaveContext(void); @@ -86,8 +86,8 @@ static void pgvRestoreContext(void); /* Constructors */ static void makePackHTAB(Package *package, bool is_trans); -static inline ChangedObject *makeChangedObject(TransObject *object, - MemoryContext ctx); +static inline ChangedObject * makeChangedObject(TransObject *object, + MemoryContext ctx); static void initObjectHistory(TransObject *object, TransObjectType type); /* Hook functions */ @@ -105,7 +105,7 @@ do { \ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), \ errmsg("variable name can not be NULL"))); \ } while(0) -#else /* PG_VERSION_NUM < 120000 */ +#else /* PG_VERSION_NUM < 120000 */ #define CHECK_ARGS_FOR_NULL() \ do { \ if (fcinfo->argnull[0]) \ @@ -117,13 +117,14 @@ do { \ (errcode(ERRCODE_INVALID_PARAMETER_VALUE), \ errmsg("variable name can not be NULL"))); \ } while(0) -#endif /* PG_VERSION_NUM */ +#endif /* PG_VERSION_NUM */ static HTAB *packagesHash = NULL; static MemoryContext ModuleContext = NULL; /* Recent package */ static Package *LastPackage = NULL; + /* Recent variable */ static Variable *LastVariable = NULL; @@ -154,18 +155,18 @@ static List *packages_stats = NIL; typedef struct tagVariableStatEntry { - HTAB *hash; - HASH_SEQ_STATUS *status; - Variable *variable; - Package *package; - Levels levels; -} VariableStatEntry; + HTAB *hash; + HASH_SEQ_STATUS *status; + Variable *variable; + Package *package; + Levels levels; +} VariableStatEntry; typedef struct tagPackageStatEntry { - HASH_SEQ_STATUS *status; - Levels levels; -} PackageStatEntry; + HASH_SEQ_STATUS *status; + Levels levels; +} PackageStatEntry; #ifdef PGPRO_EE /* @@ -174,14 +175,14 @@ typedef struct tagPackageStatEntry */ typedef struct PgvContextStruct { - dlist_head *changesStack; - MemoryContext changesStackContext; + dlist_head *changesStack; + MemoryContext changesStackContext; struct PgvContextStruct *next; } PgvContextStruct; static PgvContextStruct *pgv_context = NULL; -#endif /* PGPRO_EE */ +#endif /* PGPRO_EE */ /* * Compare functions for VariableStatEntry and PackageStatEntry members. @@ -215,7 +216,7 @@ VariableStatEntry_level_eq(void *entry, void *value) { return #ifdef PGPRO_EE - /* Compare ATX level */ + /* Compare ATX level */ ((VariableStatEntry *) entry)->levels.atxlevel == ((Levels *) value)->atxlevel && #endif ((VariableStatEntry *) entry)->levels.level == ((Levels *) value)->level; @@ -232,7 +233,7 @@ PackageStatEntry_level_eq(void *entry, void *value) { return #ifdef PGPRO_EE - /* Compare ATX level */ + /* Compare ATX level */ ((PackageStatEntry *) entry)->levels.atxlevel == ((Levels *) value)->atxlevel && #endif ((PackageStatEntry *) entry)->levels.level == ((Levels *) value)->level; @@ -276,20 +277,22 @@ PackageStatEntry_status_ptr(void *entry) */ typedef struct tagRemoveIfContext { - List **list; /* target list */ - void *value; /* value to compare with */ - bool (*eq)(void *, void *); /* list item eq to value func */ - HASH_SEQ_STATUS * (*getter)(void *); /* status getter */ - bool match_first; /* return on first match */ - bool term; /* hash_seq_term on match */ -} RemoveIfContext; + List **list; /* target list */ + void *value; /* value to compare with */ + bool (*eq) (void *, void *); /* list item eq to value func */ + HASH_SEQ_STATUS *(*getter) (void *); /* status getter */ + bool match_first; /* return on first match */ + bool term; /* hash_seq_term on match */ +} RemoveIfContext; static void list_remove_if(RemoveIfContext ctx) { #if (PG_VERSION_NUM < 130000) - ListCell *cell, *next, *prev = NULL; - void *entry = NULL; + ListCell *cell, + *next, + *prev = NULL; + void *entry = NULL; for (cell = list_head(*ctx.list); cell; cell = next) { @@ -316,12 +319,13 @@ list_remove_if(RemoveIfContext ctx) } #else /* - * See https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=1cff1b95ab6ddae32faa3efe0d95a820dbfdc164 + * See + * https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=1cff1b95ab6ddae32faa3efe0d95a820dbfdc164 * * Version >= 13 have different lists interface. */ - ListCell *cell; - void *entry = NULL; + ListCell *cell; + void *entry = NULL; foreach(cell, *ctx.list) { @@ -352,13 +356,14 @@ remove_variables_status(List **list, HASH_SEQ_STATUS *status) { RemoveIfContext ctx = { - .list = list, - .value = status, - .eq = VariableStatEntry_status_eq, - .getter = VariableStatEntry_status_ptr, + .list = list, + .value = status, + .eq = VariableStatEntry_status_eq, + .getter = VariableStatEntry_status_ptr, .match_first = true, - .term = false + .term = false }; + list_remove_if(ctx); } @@ -374,13 +379,14 @@ remove_variables_variable(List **list, Variable *variable) */ RemoveIfContext ctx = { - .list = list, - .value = variable, - .eq = VariableStatEntry_variable_eq, - .getter = VariableStatEntry_status_ptr, + .list = list, + .value = variable, + .eq = VariableStatEntry_variable_eq, + .getter = VariableStatEntry_status_ptr, .match_first = false, - .term = true + .term = true }; + list_remove_if(ctx); } @@ -392,13 +398,14 @@ remove_variables_package(List **list, Package *package) { RemoveIfContext ctx = { - .list = list, - .value = package, - .eq = VariableStatEntry_package_eq, - .getter = VariableStatEntry_status_ptr, + .list = list, + .value = package, + .eq = VariableStatEntry_package_eq, + .getter = VariableStatEntry_status_ptr, .match_first = false, - .term = true + .term = true }; + list_remove_if(ctx); } @@ -410,13 +417,14 @@ remove_variables_level(List **list, Levels *levels) { RemoveIfContext ctx = { - .list = list, - .value = levels, - .eq = VariableStatEntry_level_eq, - .getter = VariableStatEntry_status_ptr, + .list = list, + .value = levels, + .eq = VariableStatEntry_level_eq, + .getter = VariableStatEntry_status_ptr, .match_first = false, - .term = false + .term = false }; + list_remove_if(ctx); } @@ -428,13 +436,14 @@ remove_variables_all(List **list) { RemoveIfContext ctx = { - .list = list, - .value = NULL, - .eq = VariableStatEntry_eq_all, - .getter = VariableStatEntry_status_ptr, + .list = list, + .value = NULL, + .eq = VariableStatEntry_eq_all, + .getter = VariableStatEntry_status_ptr, .match_first = false, - .term = true + .term = true }; + list_remove_if(ctx); } @@ -446,13 +455,14 @@ remove_packages_status(List **list, HASH_SEQ_STATUS *status) { RemoveIfContext ctx = { - .list = list, - .value = status, - .eq = PackageStatEntry_status_eq, - .getter = PackageStatEntry_status_ptr, + .list = list, + .value = status, + .eq = PackageStatEntry_status_eq, + .getter = PackageStatEntry_status_ptr, .match_first = true, - .term = false + .term = false }; + list_remove_if(ctx); } @@ -464,13 +474,14 @@ remove_packages_level(List **list, Levels *levels) { RemoveIfContext ctx = { - .list = list, - .value = levels, - .eq = PackageStatEntry_level_eq, - .getter = PackageStatEntry_status_ptr, + .list = list, + .value = levels, + .eq = PackageStatEntry_level_eq, + .getter = PackageStatEntry_status_ptr, .match_first = false, - .term = true + .term = true }; + list_remove_if(ctx); } @@ -483,18 +494,20 @@ remove_variables_transactional(List **list) { RemoveIfContext ctx = { - .list = list, - .value = NULL, - .eq = VariableStatEntry_is_transactional, - .getter = VariableStatEntry_status_ptr, + .list = list, + .value = NULL, + .eq = VariableStatEntry_is_transactional, + .getter = VariableStatEntry_status_ptr, .match_first = false, - .term = true + .term = true }; + list_remove_if(ctx); } #endif static void freeStatsLists(void); + /* Returns a lists of packages and variables changed at current subxact level */ #define get_actual_changes_list() \ ( \ @@ -530,7 +543,7 @@ static void variable_set(text *package_name, text *var_name, Oid typid, Datum value, bool is_null, bool is_transactional) { - Package *package; + Package *package; Variable *variable; ScalarVar *scalar; @@ -561,7 +574,7 @@ static Datum variable_get(text *package_name, text *var_name, Oid typid, bool *is_null, bool strict) { - Package *package; + Package *package; Variable *variable; ScalarVar *scalar; @@ -675,7 +688,7 @@ variable_insert(PG_FUNCTION_ARGS) text *package_name; text *var_name; HeapTupleHeader rec; - Package *package; + Package *package; Variable *variable; bool is_transactional; @@ -790,7 +803,7 @@ variable_update(PG_FUNCTION_ARGS) text *package_name; text *var_name; HeapTupleHeader rec; - Package *package; + Package *package; Variable *variable; TransObject *transObject; bool res; @@ -870,7 +883,7 @@ variable_delete(PG_FUNCTION_ARGS) Oid value_type; Datum value; bool value_is_null = PG_ARGISNULL(2); - Package *package; + Package *package; Variable *variable; TransObject *transObject; bool res; @@ -944,10 +957,10 @@ variable_select(PG_FUNCTION_ARGS) FuncCallContext *funcctx; HASH_SEQ_STATUS *rstat; HashRecordEntry *item; - text *package_name; - text *var_name; - Package *package; - Variable *variable; + text *package_name; + text *var_name; + Package *package; + Variable *variable; CHECK_ARGS_FOR_NULL(); @@ -961,9 +974,9 @@ variable_select(PG_FUNCTION_ARGS) if (SRF_IS_FIRSTCALL()) { - MemoryContext oldcontext; - RecordVar *record; - VariableStatEntry *entry; + MemoryContext oldcontext; + RecordVar *record; + VariableStatEntry *entry; record = &(GetActualValue(variable).record); funcctx = SRF_FIRSTCALL_INIT(); @@ -985,7 +998,7 @@ variable_select(PG_FUNCTION_ARGS) #ifdef PGPRO_EE entry->levels.atxlevel = getNestLevelATX(); #endif - variables_stats = lcons((void *)entry, variables_stats); + variables_stats = lcons((void *) entry, variables_stats); MemoryContextSwitchTo(oldcontext); PG_FREE_IF_COPY(package_name, 0); @@ -1000,7 +1013,7 @@ variable_select(PG_FUNCTION_ARGS) if (item != NULL) { Assert(!HeapTupleHeaderHasExternal( - (HeapTupleHeader) DatumGetPointer(item->tuple))); + (HeapTupleHeader) DatumGetPointer(item->tuple))); SRF_RETURN_NEXT(funcctx, item->tuple); } @@ -1019,7 +1032,7 @@ variable_select_by_value(PG_FUNCTION_ARGS) Oid value_type; Datum value; bool value_is_null = PG_ARGISNULL(2); - Package *package; + Package *package; Variable *variable; HashRecordEntry *item; @@ -1067,7 +1080,7 @@ variable_select_by_value(PG_FUNCTION_ARGS) if (found) { Assert(!HeapTupleHeaderHasExternal( - (HeapTupleHeader) DatumGetPointer(item->tuple))); + (HeapTupleHeader) DatumGetPointer(item->tuple))); PG_RETURN_DATUM(item->tuple); } @@ -1096,7 +1109,7 @@ variable_select_by_values(PG_FUNCTION_ARGS) text *package_name; text *var_name; ArrayType *values; - Package *package; + Package *package; Variable *variable; MemoryContext oldcontext; @@ -1161,7 +1174,7 @@ variable_select_by_values(PG_FUNCTION_ARGS) if (found) { Assert(!HeapTupleHeaderHasExternal( - (HeapTupleHeader) DatumGetPointer(item->tuple))); + (HeapTupleHeader) DatumGetPointer(item->tuple))); SRF_RETURN_NEXT(funcctx, item->tuple); } } @@ -1179,7 +1192,7 @@ variable_exists(PG_FUNCTION_ARGS) { text *package_name; text *var_name; - Package *package; + Package *package; Variable *variable = NULL; char key[NAMEDATALEN]; bool found = false; @@ -1241,11 +1254,11 @@ package_exists(PG_FUNCTION_ARGS) Datum remove_variable(PG_FUNCTION_ARGS) { - text *package_name; - text *var_name; - Package *package; - Variable *variable; - TransObject *transObject; + text *package_name; + text *var_name; + Package *package; + Variable *variable; + TransObject *transObject; CHECK_ARGS_FOR_NULL(); @@ -1293,7 +1306,7 @@ remove_variable(PG_FUNCTION_ARGS) Datum remove_package(PG_FUNCTION_ARGS) { - Package *package; + Package *package; text *package_name; if (PG_ARGISNULL(0)) @@ -1317,11 +1330,11 @@ remove_package(PG_FUNCTION_ARGS) static void removePackageInternal(Package *package) { - TransObject *transObject; - Variable *variable; - HTAB *htab; - HASH_SEQ_STATUS vstat; - int i; + TransObject *transObject; + Variable *variable; + HTAB *htab; + HASH_SEQ_STATUS vstat; + int i; /* Mark all the valid variables from package as deleted */ for (i = 0; i < 2; i++) @@ -1362,7 +1375,7 @@ removePackageInternal(Package *package) static bool isPackageEmpty(Package *package) { - int var_num = GetPackState(package)->trans_var_num; + int var_num = GetPackState(package)->trans_var_num; if (package->varHashRegular) var_num += hash_get_num_entries(package->varHashRegular); @@ -1389,7 +1402,7 @@ resetVariablesCache(void) Datum remove_packages(PG_FUNCTION_ARGS) { - Package *package; + Package *package; HASH_SEQ_STATUS pstat; /* There is no any packages and variables */ @@ -1451,7 +1464,7 @@ get_packages_and_variables(PG_FUNCTION_ARGS) */ if (packagesHash) { - Package *package; + Package *package; HASH_SEQ_STATUS pstat; int mRecs = NUMVARIABLES, nRecs = 0; @@ -1473,7 +1486,8 @@ get_packages_and_variables(PG_FUNCTION_ARGS) /* Get variables list for package */ for (i = 0; i < 2; i++) { - HTAB *htab = pack_htab(package, i); + HTAB *htab = pack_htab(package, i); + if (!htab) continue; hash_seq_init(&vstat, htab); @@ -1579,7 +1593,7 @@ get_packages_stats(PG_FUNCTION_ARGS) FuncCallContext *funcctx; MemoryContext oldcontext; HASH_SEQ_STATUS *rstat; - Package *package; + Package *package; if (SRF_IS_FIRSTCALL()) { @@ -1603,7 +1617,7 @@ get_packages_stats(PG_FUNCTION_ARGS) */ if (packagesHash) { - MemoryContext ctx; + MemoryContext ctx; PackageStatEntry *entry; ctx = MemoryContextSwitchTo(TopTransactionContext); @@ -1618,7 +1632,7 @@ get_packages_stats(PG_FUNCTION_ARGS) #ifdef PGPRO_EE entry->levels.atxlevel = getNestLevelATX(); #endif - packages_stats = lcons((void *)entry, packages_stats); + packages_stats = lcons((void *) entry, packages_stats); MemoryContextSwitchTo(ctx); } else @@ -1709,9 +1723,9 @@ ensurePackagesHashExists(void) packagesHash = hash_create("Packages hash", NUMPACKAGES, &ctl, HASH_ELEM | -# if PG_VERSION_NUM >= 140000 +#if PG_VERSION_NUM >= 140000 HASH_STRINGS | -# endif +#endif HASH_CONTEXT); } @@ -1721,10 +1735,10 @@ ensurePackagesHashExists(void) static void makePackHTAB(Package *package, bool is_trans) { - HASHCTL ctl; - char hash_name[BUFSIZ]; - HTAB **htab; - MemoryContext *context; + HASHCTL ctl; + char hash_name[BUFSIZ]; + HTAB **htab; + MemoryContext *context; htab = is_trans ? &package->varHashTransact : &package->varHashRegular; context = is_trans ? &package->hctxTransact : &package->hctxRegular; @@ -1740,9 +1754,9 @@ makePackHTAB(Package *package, bool is_trans) *htab = hash_create(hash_name, NUMVARIABLES, &ctl, HASH_ELEM | -# if PG_VERSION_NUM >= 140000 +#if PG_VERSION_NUM >= 140000 HASH_STRINGS | -# endif +#endif HASH_CONTEXT); } @@ -1761,13 +1775,14 @@ initObjectHistory(TransObject *object, TransObjectType type) /* Initialize state */ state->is_valid = true; if (type == TRANS_PACKAGE) - ((PackState *)state)->trans_var_num = 0; + ((PackState *) state)->trans_var_num = 0; else { - Variable *variable = (Variable *) object; + Variable *variable = (Variable *) object; + if (!variable->is_record) { - VarState * varState = (VarState *) state; + VarState *varState = (VarState *) state; ScalarVar *scalar = &(varState->value.scalar); get_typlenbyval(variable->typid, &scalar->typlen, @@ -1780,7 +1795,7 @@ initObjectHistory(TransObject *object, TransObjectType type) static Package * getPackage(text *name, bool strict) { - Package *package; + Package *package; char key[NAMEDATALEN]; bool found; @@ -1793,8 +1808,8 @@ getPackage(text *name, bool strict) if (found && GetActualState(package)->is_valid) { - Assert (GetPackState(package)->trans_var_num + - numOfRegVars(package) > 0); + Assert(GetPackState(package)->trans_var_num + + numOfRegVars(package) > 0); return package; } } @@ -1802,7 +1817,7 @@ getPackage(text *name, bool strict) if (strict) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized package \"%s\"", key))); + errmsg("unrecognized package \"%s\"", key))); return NULL; } @@ -1810,7 +1825,7 @@ getPackage(text *name, bool strict) static Package * createPackage(text *name, bool is_trans) { - Package *package; + Package *package; char key[NAMEDATALEN]; bool found; @@ -1905,19 +1920,19 @@ getVariableInternal(Package *package, text *name, Oid typid, bool is_record, if (variable->typid != typid) { char *var_type = DatumGetCString( - DirectFunctionCall1(regtypeout, - ObjectIdGetDatum(variable->typid))); + DirectFunctionCall1(regtypeout, + ObjectIdGetDatum(variable->typid))); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("variable \"%s\" requires \"%s\" value", + errmsg("variable \"%s\" requires \"%s\" value", key, var_type))); } if (variable->is_record != is_record) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("\"%s\" isn't a %s variable", + errmsg("\"%s\" isn't a %s variable", key, is_record ? "record" : "scalar"))); } if (!GetActualState(variable)->is_valid && strict) @@ -1964,7 +1979,7 @@ createVariableInternal(Package *package, text *name, Oid typid, bool is_record, if (found) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("variable \"%s\" already created as %sTRANSACTIONAL", + errmsg("variable \"%s\" already created as %sTRANSACTIONAL", key, is_transactional ? "NOT " : ""))); } @@ -1991,7 +2006,7 @@ createVariableInternal(Package *package, text *name, Oid typid, bool is_record, ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("\"%s\" isn't a %s variable", - key, is_record ? "record" : "scalar"))); + key, is_record ? "record" : "scalar"))); /* * Savepoint must be created when variable changed in current @@ -2023,8 +2038,8 @@ createVariableInternal(Package *package, text *name, Oid typid, bool is_record, } /* - * If the variable has been created or has just become valid, - * increment the counter of valid transactional variables. + * If the variable has been created or has just become valid, increment + * the counter of valid transactional variables. */ if (is_transactional && (!found || !GetActualState(variable)->is_valid)) @@ -2109,12 +2124,13 @@ removeObject(TransObject *object, TransObjectType type) { bool found; HTAB *hash; - Package *package = NULL; + Package *package = NULL; if (type == TRANS_PACKAGE) { #ifdef PGPRO_EE - PackageContext *context, *next; + PackageContext *context, + *next; #endif package = (Package *) object; @@ -2125,6 +2141,7 @@ removeObject(TransObject *object, TransObjectType type) if (package->hctxTransact) MemoryContextDelete(package->hctxTransact); #ifdef PGPRO_EE + /* * Remove contexts with transactional part (stored when switching to * ATX transaction) @@ -2141,11 +2158,12 @@ removeObject(TransObject *object, TransObjectType type) } else { - Variable *var = (Variable *) object; + Variable *var = (Variable *) object; + package = var->package; hash = var->is_transactional ? - var->package->varHashTransact : - var->package->varHashRegular; + var->package->varHashTransact : + var->package->varHashRegular; } /* Remove all object's states */ @@ -2180,7 +2198,7 @@ createSavepoint(TransObject *object, TransObjectType type) { newState = (TransState *) MemoryContextAllocZero(ModuleContext, sizeof(PackState)); - ((PackState *)newState)->trans_var_num = ((PackState *)prevState)->trans_var_num; + ((PackState *) newState)->trans_var_num = ((PackState *) prevState)->trans_var_num; } else { @@ -2227,7 +2245,7 @@ rollbackSavepoint(TransObject *object, TransObjectType type) if (dlist_is_empty(&object->states)) { /* ...but object is a package and has some regular variables... */ - if (numOfRegVars((Package *)object) > 0) + if (numOfRegVars((Package *) object) > 0) { /* ...create a new state to make package valid. */ initObjectHistory(object, type); @@ -2242,11 +2260,12 @@ rollbackSavepoint(TransObject *object, TransObjectType type) /* ...or remove an object if it is no longer needed. */ removeObject(object, type); } + /* - * But if a package has more states, but hasn't valid variables, - * mark it as not valid or remove at top level transaction. - */ - else if (isPackageEmpty((Package *)object)) + * But if a package has more states, but hasn't valid variables, mark + * it as not valid or remove at top level transaction. + */ + else if (isPackageEmpty((Package *) object)) { if (dlist_is_empty(changesStack)) { @@ -2281,33 +2300,40 @@ static void releaseSavepoint(TransObject *object, TransObjectType type) { dlist_head *states = &object->states; + Assert(GetActualState(object)->levels.level == GetCurrentTransactionNestLevel()); /* - * If the object is not valid and does not exist at a higher level - * (or if we complete the transaction) - remove object. + * If the object is not valid and does not exist at a higher level (or if + * we complete the transaction) - remove object. */ if (!GetActualState(object)->is_valid && - (!dlist_has_next(states, dlist_head_node(states)) || - dlist_is_empty(changesStack)) + (!dlist_has_next(states, dlist_head_node(states)) || + dlist_is_empty(changesStack)) ) { removeObject(object, type); return; } - /* If object has been changed in upper level - - * replace state of that level with the current one. */ + /* + * If object has been changed in upper level - replace state of that level + * with the current one. + */ if (isObjectChangedInUpperTrans(object)) { TransState *stateToDelete; dlist_node *nodeToDelete; + nodeToDelete = dlist_next_node(states, dlist_head_node(states)); stateToDelete = dlist_container(TransState, node, nodeToDelete); removeState(object, type, stateToDelete); } - /* If the object does not yet have a record in previous level changesStack, - * create it. */ + + /* + * If the object does not yet have a record in previous level + * changesStack, create it. + */ else if (!dlist_is_empty(changesStack)) addToChangesStackUpperLevel(object, type); @@ -2320,15 +2346,16 @@ addToChangesStackUpperLevel(TransObject *object, TransObjectType type) { ChangedObject *co_new; ChangesStackNode *csn; + /* - * Impossible to push in upper list existing node - * because it was created in another context + * Impossible to push in upper list existing node because it was created + * in another context */ csn = dlist_head_element(ChangesStackNode, node, changesStack); co_new = makeChangedObject(object, csn->ctx); dlist_push_head(type == TRANS_PACKAGE ? csn->changedPacksList : - csn->changedVarsList, - &co_new->node); + csn->changedVarsList, + &co_new->node); } /* @@ -2345,10 +2372,11 @@ isObjectChangedInCurrentTrans(TransObject *object) state = GetActualState(object); return #ifdef PGPRO_EE - /* - * We should separate states with equal subxacts but with - * different ATX level - */ + + /* + * We should separate states with equal subxacts but with different ATX + * level + */ state->levels.atxlevel == getNestLevelATX() && #endif state->levels.level == GetCurrentTransactionNestLevel(); @@ -2373,10 +2401,11 @@ isObjectChangedInUpperTrans(TransObject *object) prev_state = dlist_container(TransState, node, cur_state->node.next); return #ifdef PGPRO_EE - /* - * We should separate states with equal subxacts but with - * different ATX level - */ + + /* + * We should separate states with equal subxacts but with different + * ATX level + */ prev_state->levels.atxlevel == getNestLevelATX() && #endif prev_state->levels.level == GetCurrentTransactionNestLevel() - 1; @@ -2384,10 +2413,11 @@ isObjectChangedInUpperTrans(TransObject *object) else return #ifdef PGPRO_EE - /* - * We should separate states with equal subxacts but with - * different ATX level - */ + + /* + * We should separate states with equal subxacts but with different + * ATX level + */ cur_state->levels.atxlevel == getNestLevelATX() && #endif cur_state->levels.level == GetCurrentTransactionNestLevel() - 1; @@ -2518,9 +2548,7 @@ processChanges(Action action) dlist_pop_head_node(changesStack)); /* - * i: - * 1 - manage variables - * 0 - manage packages + * i: 1 - manage variables 0 - manage packages */ for (i = 1; i > -1; i--) { @@ -2548,7 +2576,7 @@ processChanges(Action action) if (i) { Variable *variable = (Variable *) object; - Package *package = variable->package; + Package *package = variable->package; if (!GetActualState(package)->is_valid) GetActualState(variable)->is_valid = false; @@ -2586,19 +2614,20 @@ processChanges(Action action) static void compatibility_check(void) { - /* - * | Edition | ConnPool | - * ---------------------- - * | std 9.6 | no | - * | std 10 | no | - * | std 11 | no | - * | std 12 | no | - * | std 13 | no | - * | ee 9.6 | no | - * | ee 10 | no | - * | ee 11 | yes | - * | ee 12 | yes | - * | ee 13 | yes | + /* ---------------------- + * | Edition | ConnPool | + * ---------------------- + * | std 9.6 | no | + * | std 10 | no | + * | std 11 | no | + * | std 12 | no | + * | std 13 | no | + * | ee 9.6 | no | + * | ee 10 | no | + * | ee 11 | yes | + * | ee 12 | yes | + * | ee 13 | yes | + * ---------------------- */ #if defined(PGPRO_EE) && PG_VERSION_NUM >= 110000 if (!IsDedicatedBackend) @@ -2606,7 +2635,7 @@ compatibility_check(void) freeStatsLists(); elog(ERROR, "pg_variables extension is incompatible with connection pooling"); } -#endif /* PGPRO_EE */ +#endif /* PGPRO_EE */ } #ifdef PGPRO_EE @@ -2617,10 +2646,10 @@ compatibility_check(void) static void pgvSaveContext(void) { - Package *package; - HASH_SEQ_STATUS pstat; - PgvContextStruct *sus = MemoryContextAlloc(CurTransactionContext, - sizeof(PgvContextStruct)); + Package *package; + HASH_SEQ_STATUS pstat; + PgvContextStruct *sus = MemoryContextAlloc(CurTransactionContext, + sizeof(PgvContextStruct)); /* Save transactional variables for all packages (in packages structs) */ if (packagesHash != NULL) @@ -2630,25 +2659,26 @@ pgvSaveContext(void) while ((package = (Package *) hash_seq_search(&pstat)) != NULL) { PackageContext *context = MemoryContextAlloc(ModuleContext, - sizeof(PackageContext)); + sizeof(PackageContext)); + context->next = package->context; package->context = context; /* Save transactional variables in context */ context->hctxTransact = package->hctxTransact; context->varHashTransact = package->varHashTransact; + /* - * Package structure has a transactional part 'transObject'. - * This part is used in asserts like + * Package structure has a transactional part 'transObject'. This + * part is used in asserts like * Assert(GetActualState(object)->levels.level == - * GetCurrentTransactionNestLevel()) - * But this comparison is not valid for ATX transactions because + * GetCurrentTransactionNestLevel()) But this comparison is not + * valid for ATX transactions because * 'CurrentTransactionState->nestingLevel' for each of new ATX * level is starts with 1. We should save package state at start - * of ATX transaction and restore it at finish. - * No need do this for transactional variables (we clean them at - * end of ATX transaction) and regular variables (we modify them - * directly). + * of ATX transaction and restore it at finish. No need do this + * for transactional variables (we clean them at end of ATX + * transaction) and regular variables (we modify them directly). */ context->state = GetActualState(&package->transObject); @@ -2676,9 +2706,9 @@ pgvSaveContext(void) static void pgvRestoreContext() { - Package *package; - HASH_SEQ_STATUS pstat; - PgvContextStruct *sus = pgv_context; + Package *package; + HASH_SEQ_STATUS pstat; + PgvContextStruct *sus = pgv_context; resetVariablesCache(); /* Delete changes stack for all transactional variables */ @@ -2699,8 +2729,8 @@ pgvRestoreContext() while ((package = (Package *) hash_seq_search(&pstat)) != NULL) { /* - * Delete context with transactional variables (they are - * no need outside ATX transaction) + * Delete context with transactional variables (they are no need + * outside ATX transaction) */ if (package->hctxTransact) MemoryContextDelete(package->hctxTransact); @@ -2708,10 +2738,10 @@ pgvRestoreContext() /* We have stored context for this package? */ if (package->context) { - PackageContext *context = package->context; - PackageContext *next = context->next; - TransObject *object = &package->transObject; - TransState *state; + PackageContext *context = package->context; + PackageContext *next = context->next; + TransObject *object = &package->transObject; + TransState *state; /* Restore transactional variables from context */ package->hctxTransact = context->hctxTransact; @@ -2722,7 +2752,7 @@ pgvRestoreContext() { if (dlist_is_empty(&object->states)) elog(ERROR, "pg_variables extension can not find " - "transaction state for package"); + "transaction state for package"); removeState(object, TRANS_PACKAGE, state); } @@ -2734,6 +2764,7 @@ pgvRestoreContext() /* Package was created in this autonomous transaction */ package->hctxTransact = NULL; package->varHashTransact = NULL; + /* * No need to remove package states: for just created package * we have one state with level = 0 @@ -2743,8 +2774,8 @@ pgvRestoreContext() } /* - * 'sus' can be NULL in case pg_variables was not initialized - * at start of transaction + * 'sus' can be NULL in case pg_variables was not initialized at start of + * transaction */ if (sus) { @@ -2756,7 +2787,7 @@ pgvRestoreContext() pfree(sus); } } -#endif /* PGPRO_EE */ +#endif /* PGPRO_EE */ /* * Intercept execution during subtransaction processing @@ -2765,7 +2796,7 @@ static void pgvSubTransCallback(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg) { - Levels levels; + Levels levels; if (changesStack) { @@ -2829,13 +2860,13 @@ pgvTransCallback(XactEvent event, void *arg) if (getNestLevelATX() > 0) { if (event == XACT_EVENT_START) - { /* on each ATX transaction start */ + { /* on each ATX transaction start */ pgvSaveContext(); } else if (event == XACT_EVENT_ABORT || event == XACT_EVENT_PARALLEL_ABORT || event == XACT_EVENT_COMMIT || event == XACT_EVENT_PARALLEL_COMMIT || event == XACT_EVENT_PREPARE) - { /* on each ATX transaction finish */ + { /* on each ATX transaction finish */ pgvRestoreContext(); } } @@ -2857,16 +2888,17 @@ variable_ExecutorEnd(QueryDesc *queryDesc) } /* - * Free hash_seq_search scans + * Free hash_seq_search scans */ static void freeStatsLists(void) { - ListCell *cell; + ListCell *cell; foreach(cell, variables_stats) { VariableStatEntry *entry = (VariableStatEntry *) lfirst(cell); + hash_seq_term(entry->status); } @@ -2875,6 +2907,7 @@ freeStatsLists(void) foreach(cell, packages_stats) { PackageStatEntry *entry = (PackageStatEntry *) lfirst(cell); + hash_seq_term(entry->status); } diff --git a/pg_variables.h b/pg_variables.h index 864a5e2..70a9399 100644 --- a/pg_variables.h +++ b/pg_variables.h @@ -42,7 +42,7 @@ typedef struct RecordVar FmgrInfo hash_proc; /* Match function info */ FmgrInfo cmp_proc; -} RecordVar; +} RecordVar; typedef struct ScalarVar { @@ -55,9 +55,9 @@ typedef struct ScalarVar /* Object levels (subxact + atx) */ typedef struct Levels { - int level; + int level; #ifdef PGPRO_EE - int atxlevel; + int atxlevel; #endif } Levels; @@ -72,8 +72,8 @@ typedef struct TransState /* List node that stores one of the package's states */ typedef struct PackState { - TransState state; - unsigned long trans_var_num; /* Number of valid transactional variables */ + TransState state; + unsigned long trans_var_num; /* Number of valid transactional variables */ } PackState; /* List node that stores one of the variable's states */ @@ -85,22 +85,22 @@ typedef struct VarState ScalarVar scalar; RecordVar record; } value; -} VarState; +} VarState; /* Transactional object */ typedef struct TransObject { char name[NAMEDATALEN]; dlist_head states; -} TransObject; +} TransObject; #ifdef PGPRO_EE /* Package context for save transactional part of package */ typedef struct PackageContext { - HTAB *varHashTransact; + HTAB *varHashTransact; MemoryContext hctxTransact; - TransState *state; + TransState *state; struct PackageContext *next; } PackageContext; #endif @@ -117,7 +117,7 @@ typedef struct Package #ifdef PGPRO_EE PackageContext *context; #endif -} Package; +} Package; /* Transactional variable */ typedef struct Variable @@ -125,6 +125,7 @@ typedef struct Variable TransObject transObject; Package *package; Oid typid; + /* * We need an additional flag to determine variable's type since we can * store record type DATUM within scalar variable @@ -137,7 +138,7 @@ typedef struct Variable */ bool is_transactional; bool is_deleted; -} Variable; +} Variable; typedef struct HashRecordKey { diff --git a/pg_variables_record.c b/pg_variables_record.c index 3d7ca18..99a5142 100644 --- a/pg_variables_record.c +++ b/pg_variables_record.c @@ -17,10 +17,10 @@ * Split tuptoaster.c into three separate files. */ #if PG_VERSION_NUM >= 130000 -# include "access/detoast.h" -# include "access/heaptoast.h" +#include "access/detoast.h" +#include "access/heaptoast.h" #else -# include "access/tuptoaster.h" +#include "access/tuptoaster.h" #endif #include "catalog/pg_collation.h" @@ -96,8 +96,8 @@ init_record(RecordVar *record, TupleDesc tupdesc, Variable *variable) /* * In case something went wrong, you need to roll back the changes before - * completing the transaction, because the variable may be regular - * and not present in list of changed vars. + * completing the transaction, because the variable may be regular and not + * present in list of changed vars. */ if (!OidIsValid(typentry->hash_proc_finfo.fn_oid)) { @@ -243,7 +243,7 @@ copy_record_tuple(RecordVar *record, HeapTupleHeader tupleHeader) */ if (HeapTupleHeaderHasExternal(tupleHeader)) return toast_flatten_tuple_to_datum(tupleHeader, - HeapTupleHeaderGetDatumLength(tupleHeader), + HeapTupleHeaderGetDatumLength(tupleHeader), tupdesc); /* @@ -267,9 +267,9 @@ get_record_key(Datum tuple, TupleDesc tupdesc, bool *isnull) { HeapTupleHeader th = (HeapTupleHeader) DatumGetPointer(tuple); bool hasnulls = th->t_infomask & HEAP_HASNULL; - bits8 *bp = th->t_bits; /* ptr to null bitmap in tuple */ - char *tp; /* ptr to tuple data */ - long off; /* offset in tuple data */ + bits8 *bp = th->t_bits; /* ptr to null bitmap in tuple */ + char *tp; /* ptr to tuple data */ + long off; /* offset in tuple data */ int keyatt = 0; Form_pg_attribute attr = GetTupleDescAttr(tupdesc, keyatt); From d37328be1de4ba5bba1e0302a5aee6c0bc12ddb1 Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Mon, 15 Nov 2021 18:02:54 +0300 Subject: [PATCH 24/46] Refactoring processChanges --- pg_variables.c | 83 +++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/pg_variables.c b/pg_variables.c index 46c7f24..fa4682c 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -2532,6 +2532,46 @@ typedef enum Action ROLLBACK_TO_SAVEPOINT } Action; +/* + * Apply savepoint actions on list of variables or packages. + */ +static void +applyAction(Action action, TransObjectType type, dlist_head *list) +{ + dlist_iter iter; + + dlist_foreach(iter, list) + { + ChangedObject *co = dlist_container(ChangedObject, node, iter.cur); + TransObject *object = co->object; + + switch (action) + { + case ROLLBACK_TO_SAVEPOINT: + rollbackSavepoint(object, type); + break; + case RELEASE_SAVEPOINT: + + /* + * If package was removed in current transaction level mark + * var as removed. We do not check pack_state->level, because + * var cannot get in list of changes until pack is removed. + */ + if (type == TRANS_VARIABLE) + { + Variable *variable = (Variable *) object; + Package *package = variable->package; + + if (!GetActualState(package)->is_valid) + GetActualState(variable)->is_valid = false; + } + + releaseSavepoint(object, type); + break; + } + } +} + /* * Iterate variables and packages from list of changes and * apply corresponding action on them @@ -2540,53 +2580,14 @@ static void processChanges(Action action) { ChangesStackNode *bottom_list; - int i; Assert(changesStack && changesStackContext); /* List removed from stack but we still can use it */ bottom_list = dlist_container(ChangesStackNode, node, dlist_pop_head_node(changesStack)); - /* - * i: 1 - manage variables 0 - manage packages - */ - for (i = 1; i > -1; i--) - { - dlist_iter iter; - - dlist_foreach(iter, i ? bottom_list->changedVarsList : - bottom_list->changedPacksList) - { - ChangedObject *co = dlist_container(ChangedObject, node, iter.cur); - TransObject *object = co->object; - - switch (action) - { - case ROLLBACK_TO_SAVEPOINT: - rollbackSavepoint(object, i ? TRANS_VARIABLE : TRANS_PACKAGE); - break; - case RELEASE_SAVEPOINT: - - /* - * If package was removed in current transaction level - * mark var as removed. We do not check pack_state->level, - * because var cannot get in list of changes until pack is - * removed. - */ - if (i) - { - Variable *variable = (Variable *) object; - Package *package = variable->package; - - if (!GetActualState(package)->is_valid) - GetActualState(variable)->is_valid = false; - } - - releaseSavepoint(object, i ? TRANS_VARIABLE : TRANS_PACKAGE); - break; - } - } - } + applyAction(action, TRANS_VARIABLE, bottom_list->changedVarsList); + applyAction(action, TRANS_PACKAGE, bottom_list->changedPacksList); /* Remove changes list of current level */ MemoryContextDelete(bottom_list->ctx); From e2a7231a286513453970c1d5e142c05a56234e83 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Tue, 7 Dec 2021 01:49:12 +0300 Subject: [PATCH 25/46] Added expected out-file for case (atx + in-memory extension) --- expected/pg_variables_atx_2.out | 497 ++++++++++++++++++++++++++++++++ 1 file changed, 497 insertions(+) create mode 100644 expected/pg_variables_atx_2.out diff --git a/expected/pg_variables_atx_2.out b/expected/pg_variables_atx_2.out new file mode 100644 index 0000000..c6f44a7 --- /dev/null +++ b/expected/pg_variables_atx_2.out @@ -0,0 +1,497 @@ +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------ +-- Non-transactional variables +------------------------------ +select pgv_set('vars', 'int1', 101); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102); + pgv_set +--------- + +(1 row) + + begin autonomous; + select pgv_set('vars', 'int3', 103); + pgv_set +--------- + +(1 row) + +-- 101, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 101 | 102 | 103 +(1 row) + + select pgv_set('vars', 'int1', 1001); + pgv_set +--------- + +(1 row) + + begin autonomous; +-- 1001, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 102 | 103 +(1 row) + + select pgv_set('vars', 'int2', 1002); + pgv_set +--------- + +(1 row) + + commit; + commit; +-- 1001, 1002, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 1002 | 103 +(1 row) + + select pgv_set('vars', 'int3', 1003); + pgv_set +--------- + +(1 row) + +rollback; +-- 1001, 1002, 1003: +select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 1002 | 1003 +(1 row) + +-- vars:int1, vars:int2, vars:int3: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | f + vars | int2 | f + vars | int3 | f +(3 rows) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +-------------------------- +-- Transactional variables +-------------------------- +select pgv_set('vars', 'int1', 101, true); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102, true); + pgv_set +--------- + +(1 row) + + begin autonomous; + select pgv_set('vars', 'int3', 103, true); + pgv_set +--------- + +(1 row) + +-- 103: + select pgv_get('vars', 'int3', null::int); + pgv_get +--------- + 103 +(1 row) + + begin autonomous; + select pgv_set('vars', 'int2', 1002, true); + pgv_set +--------- + +(1 row) + +-- 1002: + select pgv_get('vars', 'int2', null::int); + pgv_get +--------- + 1002 +(1 row) + + commit; +-- 103: + select pgv_get('vars', 'int3', null::int); + pgv_get +--------- + 103 +(1 row) + + commit; + select pgv_set('vars', 'int1', 1001, true); + pgv_set +--------- + +(1 row) + +-- 1001: + select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1001 +(1 row) + +-- 102: + select pgv_get('vars', 'int2', null::int); + pgv_get +--------- + 102 +(1 row) + +rollback; +-- 101: +select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 101 +(1 row) + +-- vars:int1: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | t +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +---------- +-- Cursors +---------- +select pgv_insert('test', 'x', row (1::int, 2::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (2::int, 3::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (3::int, 4::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (10::int, 20::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (20::int, 30::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (30::int, 40::int), true); + pgv_insert +------------ + +(1 row) + +begin; + declare r1_cur cursor for select pgv_select('test', 'x'); + begin autonomous; + begin autonomous; + begin autonomous; + begin autonomous; + begin autonomous; + select pgv_insert('test', 'z', row (11::int, 22::int), false); + pgv_insert +------------ + +(1 row) + + select pgv_insert('test', 'z', row (22::int, 33::int), false); + pgv_insert +------------ + +(1 row) + + select pgv_insert('test', 'z', row (33::int, 44::int), false); + pgv_insert +------------ + +(1 row) + + declare r11_cur cursor for select pgv_select('test', 'x'); +-- (1,2),(2,3): + fetch 2 in r11_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + + declare r2_cur cursor for select pgv_select('test', 'y'); +-- correct error: unrecognized variable "y" + fetch 2 in r2_cur; +ERROR: unrecognized variable "y" + rollback; + rollback; + rollback; + rollback; + rollback; + declare r2_cur cursor for select pgv_select('test', 'y'); + declare r3_cur cursor for select pgv_select('test', 'z'); +-- (1,2),(2,3): + fetch 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +-- (10,20),(20,30): + fetch 2 in r2_cur; + pgv_select +------------ + (10,20) + (20,30) +(2 rows) + +-- (11,22),(22,33): + fetch 2 in r3_cur; + pgv_select +------------ + (11,22) + (22,33) +(2 rows) + +rollback; +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------ +-- Savepoint: rollback in main transaction +------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 101, true); + pgv_set +--------- + +(1 row) + +-- 101: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 101 +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 102, true); + pgv_set +--------- + +(1 row) + +-- 102: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 102 +(1 row) + + begin autonomous; +ERROR: in_memory extension is incompatible with autonomous transactions + select pgv_set('vars', 'trans_int', 103, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 103: + select pgv_get('vars', 'trans_int', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +-- 102: + select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" + rollback to sp1; +ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks +commit; +WARNING: there is no transaction in progress +-- 101: +select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------ +-- Savepoint: rollback in autonomous transaction +------------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 1, true); + pgv_set +--------- + +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 100, true); + pgv_set +--------- + +(1 row) + + begin autonomous; +ERROR: in_memory extension is incompatible with autonomous transactions + begin autonomous; +ERROR: in_memory extension is incompatible with autonomous transactions + select pgv_set('vars1', 'int1', 2); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 3, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + savepoint sp2; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 4, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 2 + select pgv_get('vars1', 'int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 4 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback to sp2; +ERROR: savepoint "sp2" does not exist +-- 3 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- vars1:int1, vars1:trans_int1: + select * from pgv_list() order by package, name; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int2', 4, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int3', 5, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'int2', 3); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback; + commit; +WARNING: there is no transaction in progress + rollback to sp1; +ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks +-- 1 + select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" +-- 2 + select pgv_get('vars1', 'int1', null::int); +ERROR: unrecognized package "vars1" +-- 3 + select pgv_get('vars1', 'int2', null::int); +ERROR: unrecognized package "vars1" +-- vars:trans_int, vars1:int1, vars1:int2: + select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +commit; +WARNING: there is no transaction in progress +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------------------ +-- Sample with (subxact inside ATX) == (subxact outside ATX) +------------------------------------------------------------ +select pgv_set('vars1', 'int1', 0); + pgv_set +--------- + +(1 row) + +select pgv_set('vars1', 'trans_int1', 0, true); + pgv_set +--------- + +(1 row) + +begin; + begin autonomous; +ERROR: in_memory extension is incompatible with autonomous transactions + select pgv_set('vars1', 'int1', 1); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 2, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + savepoint sp2; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 3, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback to sp2; +ERROR: savepoint "sp2" does not exist +-- 2 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +rollback; +WARNING: there is no transaction in progress +-- vars1:int1, vars1:trans_int1 +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------------+------------------ + vars1 | int1 | f + vars1 | trans_int1 | t +(2 rows) + +-- 1 +select pgv_get('vars1', 'int1', null::int); + pgv_get +--------- + 0 +(1 row) + +-- 0 +select pgv_get('vars1', 'trans_int1', null::int); + pgv_get +--------- + 0 +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + From 417ade15264b09221f0eb527a6ff2ac6ebddadcc Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Tue, 7 Dec 2021 11:45:22 +0300 Subject: [PATCH 26/46] Added expected out-file for case (atx + in-memory extension) for v10,v11 --- expected/pg_variables_atx_3.out | 497 ++++++++++++++++++++++++++++++++ expected/pg_variables_atx_4.out | 497 ++++++++++++++++++++++++++++++++ 2 files changed, 994 insertions(+) create mode 100644 expected/pg_variables_atx_3.out create mode 100644 expected/pg_variables_atx_4.out diff --git a/expected/pg_variables_atx_3.out b/expected/pg_variables_atx_3.out new file mode 100644 index 0000000..ad1ae89 --- /dev/null +++ b/expected/pg_variables_atx_3.out @@ -0,0 +1,497 @@ +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------ +-- Non-transactional variables +------------------------------ +select pgv_set('vars', 'int1', 101); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102); + pgv_set +--------- + +(1 row) + + begin autonomous; + select pgv_set('vars', 'int3', 103); + pgv_set +--------- + +(1 row) + +-- 101, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 101 | 102 | 103 +(1 row) + + select pgv_set('vars', 'int1', 1001); + pgv_set +--------- + +(1 row) + + begin autonomous; +-- 1001, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 102 | 103 +(1 row) + + select pgv_set('vars', 'int2', 1002); + pgv_set +--------- + +(1 row) + + commit; + commit; +-- 1001, 1002, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 1002 | 103 +(1 row) + + select pgv_set('vars', 'int3', 1003); + pgv_set +--------- + +(1 row) + +rollback; +-- 1001, 1002, 1003: +select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 1002 | 1003 +(1 row) + +-- vars:int1, vars:int2, vars:int3: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | f + vars | int2 | f + vars | int3 | f +(3 rows) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +-------------------------- +-- Transactional variables +-------------------------- +select pgv_set('vars', 'int1', 101, true); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102, true); + pgv_set +--------- + +(1 row) + + begin autonomous; + select pgv_set('vars', 'int3', 103, true); + pgv_set +--------- + +(1 row) + +-- 103: + select pgv_get('vars', 'int3', null::int); + pgv_get +--------- + 103 +(1 row) + + begin autonomous; + select pgv_set('vars', 'int2', 1002, true); + pgv_set +--------- + +(1 row) + +-- 1002: + select pgv_get('vars', 'int2', null::int); + pgv_get +--------- + 1002 +(1 row) + + commit; +-- 103: + select pgv_get('vars', 'int3', null::int); + pgv_get +--------- + 103 +(1 row) + + commit; + select pgv_set('vars', 'int1', 1001, true); + pgv_set +--------- + +(1 row) + +-- 1001: + select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1001 +(1 row) + +-- 102: + select pgv_get('vars', 'int2', null::int); + pgv_get +--------- + 102 +(1 row) + +rollback; +-- 101: +select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 101 +(1 row) + +-- vars:int1: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | t +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +---------- +-- Cursors +---------- +select pgv_insert('test', 'x', row (1::int, 2::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (2::int, 3::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (3::int, 4::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (10::int, 20::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (20::int, 30::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (30::int, 40::int), true); + pgv_insert +------------ + +(1 row) + +begin; + declare r1_cur cursor for select pgv_select('test', 'x'); + begin autonomous; + begin autonomous; + begin autonomous; + begin autonomous; + begin autonomous; + select pgv_insert('test', 'z', row (11::int, 22::int), false); + pgv_insert +------------ + +(1 row) + + select pgv_insert('test', 'z', row (22::int, 33::int), false); + pgv_insert +------------ + +(1 row) + + select pgv_insert('test', 'z', row (33::int, 44::int), false); + pgv_insert +------------ + +(1 row) + + declare r11_cur cursor for select pgv_select('test', 'x'); +-- (1,2),(2,3): + fetch 2 in r11_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + + declare r2_cur cursor for select pgv_select('test', 'y'); +-- correct error: unrecognized variable "y" + fetch 2 in r2_cur; +ERROR: unrecognized variable "y" + rollback; + rollback; + rollback; + rollback; + rollback; + declare r2_cur cursor for select pgv_select('test', 'y'); + declare r3_cur cursor for select pgv_select('test', 'z'); +-- (1,2),(2,3): + fetch 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +-- (10,20),(20,30): + fetch 2 in r2_cur; + pgv_select +------------ + (10,20) + (20,30) +(2 rows) + +-- (11,22),(22,33): + fetch 2 in r3_cur; + pgv_select +------------ + (11,22) + (22,33) +(2 rows) + +rollback; +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------ +-- Savepoint: rollback in main transaction +------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 101, true); + pgv_set +--------- + +(1 row) + +-- 101: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 101 +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 102, true); + pgv_set +--------- + +(1 row) + +-- 102: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 102 +(1 row) + + begin autonomous; +ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling + select pgv_set('vars', 'trans_int', 103, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 103: + select pgv_get('vars', 'trans_int', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +-- 102: + select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" + rollback to sp1; +ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks +commit; +WARNING: there is no transaction in progress +-- 101: +select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------ +-- Savepoint: rollback in autonomous transaction +------------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 1, true); + pgv_set +--------- + +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 100, true); + pgv_set +--------- + +(1 row) + + begin autonomous; +ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling + begin autonomous; +ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling + select pgv_set('vars1', 'int1', 2); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 3, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + savepoint sp2; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 4, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 2 + select pgv_get('vars1', 'int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 4 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback to sp2; +ERROR: no such savepoint +-- 3 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- vars1:int1, vars1:trans_int1: + select * from pgv_list() order by package, name; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int2', 4, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int3', 5, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'int2', 3); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback; + commit; +WARNING: there is no transaction in progress + rollback to sp1; +ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks +-- 1 + select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" +-- 2 + select pgv_get('vars1', 'int1', null::int); +ERROR: unrecognized package "vars1" +-- 3 + select pgv_get('vars1', 'int2', null::int); +ERROR: unrecognized package "vars1" +-- vars:trans_int, vars1:int1, vars1:int2: + select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +commit; +WARNING: there is no transaction in progress +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------------------ +-- Sample with (subxact inside ATX) == (subxact outside ATX) +------------------------------------------------------------ +select pgv_set('vars1', 'int1', 0); + pgv_set +--------- + +(1 row) + +select pgv_set('vars1', 'trans_int1', 0, true); + pgv_set +--------- + +(1 row) + +begin; + begin autonomous; +ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling + select pgv_set('vars1', 'int1', 1); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 2, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + savepoint sp2; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 3, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback to sp2; +ERROR: no such savepoint +-- 2 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +rollback; +WARNING: there is no transaction in progress +-- vars1:int1, vars1:trans_int1 +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------------+------------------ + vars1 | int1 | f + vars1 | trans_int1 | t +(2 rows) + +-- 1 +select pgv_get('vars1', 'int1', null::int); + pgv_get +--------- + 0 +(1 row) + +-- 0 +select pgv_get('vars1', 'trans_int1', null::int); + pgv_get +--------- + 0 +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/expected/pg_variables_atx_4.out b/expected/pg_variables_atx_4.out new file mode 100644 index 0000000..914725a --- /dev/null +++ b/expected/pg_variables_atx_4.out @@ -0,0 +1,497 @@ +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------ +-- Non-transactional variables +------------------------------ +select pgv_set('vars', 'int1', 101); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102); + pgv_set +--------- + +(1 row) + + begin autonomous; + select pgv_set('vars', 'int3', 103); + pgv_set +--------- + +(1 row) + +-- 101, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 101 | 102 | 103 +(1 row) + + select pgv_set('vars', 'int1', 1001); + pgv_set +--------- + +(1 row) + + begin autonomous; +-- 1001, 102, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 102 | 103 +(1 row) + + select pgv_set('vars', 'int2', 1002); + pgv_set +--------- + +(1 row) + + commit; + commit; +-- 1001, 1002, 103: + select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 1002 | 103 +(1 row) + + select pgv_set('vars', 'int3', 1003); + pgv_set +--------- + +(1 row) + +rollback; +-- 1001, 1002, 1003: +select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); + pgv_get | pgv_get | pgv_get +---------+---------+--------- + 1001 | 1002 | 1003 +(1 row) + +-- vars:int1, vars:int2, vars:int3: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | f + vars | int2 | f + vars | int3 | f +(3 rows) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +-------------------------- +-- Transactional variables +-------------------------- +select pgv_set('vars', 'int1', 101, true); + pgv_set +--------- + +(1 row) + +begin; + select pgv_set('vars', 'int2', 102, true); + pgv_set +--------- + +(1 row) + + begin autonomous; + select pgv_set('vars', 'int3', 103, true); + pgv_set +--------- + +(1 row) + +-- 103: + select pgv_get('vars', 'int3', null::int); + pgv_get +--------- + 103 +(1 row) + + begin autonomous; + select pgv_set('vars', 'int2', 1002, true); + pgv_set +--------- + +(1 row) + +-- 1002: + select pgv_get('vars', 'int2', null::int); + pgv_get +--------- + 1002 +(1 row) + + commit; +-- 103: + select pgv_get('vars', 'int3', null::int); + pgv_get +--------- + 103 +(1 row) + + commit; + select pgv_set('vars', 'int1', 1001, true); + pgv_set +--------- + +(1 row) + +-- 1001: + select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1001 +(1 row) + +-- 102: + select pgv_get('vars', 'int2', null::int); + pgv_get +--------- + 102 +(1 row) + +rollback; +-- 101: +select pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 101 +(1 row) + +-- vars:int1: +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ + vars | int1 | t +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + +---------- +-- Cursors +---------- +select pgv_insert('test', 'x', row (1::int, 2::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (2::int, 3::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'x', row (3::int, 4::int), false); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (10::int, 20::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (20::int, 30::int), true); + pgv_insert +------------ + +(1 row) + +select pgv_insert('test', 'y', row (30::int, 40::int), true); + pgv_insert +------------ + +(1 row) + +begin; + declare r1_cur cursor for select pgv_select('test', 'x'); + begin autonomous; + begin autonomous; + begin autonomous; + begin autonomous; + begin autonomous; + select pgv_insert('test', 'z', row (11::int, 22::int), false); + pgv_insert +------------ + +(1 row) + + select pgv_insert('test', 'z', row (22::int, 33::int), false); + pgv_insert +------------ + +(1 row) + + select pgv_insert('test', 'z', row (33::int, 44::int), false); + pgv_insert +------------ + +(1 row) + + declare r11_cur cursor for select pgv_select('test', 'x'); +-- (1,2),(2,3): + fetch 2 in r11_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + + declare r2_cur cursor for select pgv_select('test', 'y'); +-- correct error: unrecognized variable "y" + fetch 2 in r2_cur; +ERROR: unrecognized variable "y" + rollback; + rollback; + rollback; + rollback; + rollback; + declare r2_cur cursor for select pgv_select('test', 'y'); + declare r3_cur cursor for select pgv_select('test', 'z'); +-- (1,2),(2,3): + fetch 2 in r1_cur; + pgv_select +------------ + (1,2) + (2,3) +(2 rows) + +-- (10,20),(20,30): + fetch 2 in r2_cur; + pgv_select +------------ + (10,20) + (20,30) +(2 rows) + +-- (11,22),(22,33): + fetch 2 in r3_cur; + pgv_select +------------ + (11,22) + (22,33) +(2 rows) + +rollback; +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------ +-- Savepoint: rollback in main transaction +------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 101, true); + pgv_set +--------- + +(1 row) + +-- 101: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 101 +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 102, true); + pgv_set +--------- + +(1 row) + +-- 102: + select pgv_get('vars', 'trans_int', null::int); + pgv_get +--------- + 102 +(1 row) + + begin autonomous; +ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling + select pgv_set('vars', 'trans_int', 103, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 103: + select pgv_get('vars', 'trans_int', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +-- 102: + select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" + rollback to sp1; +ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks +commit; +WARNING: there is no transaction in progress +-- 101: +select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------ +-- Savepoint: rollback in autonomous transaction +------------------------------------------------ +begin; + select pgv_set('vars', 'trans_int', 1, true); + pgv_set +--------- + +(1 row) + + savepoint sp1; + select pgv_set('vars', 'trans_int', 100, true); + pgv_set +--------- + +(1 row) + + begin autonomous; +ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling + begin autonomous; +ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling + select pgv_set('vars1', 'int1', 2); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 3, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + savepoint sp2; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 4, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 2 + select pgv_get('vars1', 'int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- 4 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback to sp2; +ERROR: savepoint "sp2" does not exist +-- 3 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- vars1:int1, vars1:trans_int1: + select * from pgv_list() order by package, name; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int2', 4, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int3', 5, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'int2', 3); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback; + commit; +WARNING: there is no transaction in progress + rollback to sp1; +ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks +-- 1 + select pgv_get('vars', 'trans_int', null::int); +ERROR: unrecognized package "vars" +-- 2 + select pgv_get('vars1', 'int1', null::int); +ERROR: unrecognized package "vars1" +-- 3 + select pgv_get('vars1', 'int2', null::int); +ERROR: unrecognized package "vars1" +-- vars:trans_int, vars1:int1, vars1:int2: + select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------+------------------ +(0 rows) + +commit; +WARNING: there is no transaction in progress +select pgv_free(); + pgv_free +---------- + +(1 row) + +------------------------------------------------------------ +-- Sample with (subxact inside ATX) == (subxact outside ATX) +------------------------------------------------------------ +select pgv_set('vars1', 'int1', 0); + pgv_set +--------- + +(1 row) + +select pgv_set('vars1', 'trans_int1', 0, true); + pgv_set +--------- + +(1 row) + +begin; + begin autonomous; +ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling + select pgv_set('vars1', 'int1', 1); +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 2, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + savepoint sp2; +ERROR: current transaction is aborted, commands ignored until end of transaction block + select pgv_set('vars1', 'trans_int1', 3, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + rollback to sp2; +ERROR: savepoint "sp2" does not exist +-- 2 + select pgv_get('vars1', 'trans_int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + commit; +rollback; +WARNING: there is no transaction in progress +-- vars1:int1, vars1:trans_int1 +select * from pgv_list() order by package, name; + package | name | is_transactional +---------+------------+------------------ + vars1 | int1 | f + vars1 | trans_int1 | t +(2 rows) + +-- 1 +select pgv_get('vars1', 'int1', null::int); + pgv_get +--------- + 0 +(1 row) + +-- 0 +select pgv_get('vars1', 'trans_int1', null::int); + pgv_get +--------- + 0 +(1 row) + +select pgv_free(); + pgv_free +---------- + +(1 row) + From 720adc855ac0f659de15fb36a2133af94478e7fc Mon Sep 17 00:00:00 2001 From: Sofia Kopikova Date: Mon, 27 Dec 2021 00:54:00 +0300 Subject: [PATCH 27/46] replace UNKNOWNOID to TEXTOID --- expected/pg_variables.out | 54 +++++++++++--- expected/pg_variables_trans.out | 4 +- pg_variables.c | 34 ++++++++- pg_variables.h | 7 +- pg_variables_record.c | 122 +++++++++++++++++++++++++++++++- sql/pg_variables.sql | 16 +++-- sql/pg_variables_trans.sql | 2 +- 7 files changed, 220 insertions(+), 19 deletions(-) diff --git a/expected/pg_variables.out b/expected/pg_variables.out index 180ebd1..1e5bee6 100644 --- a/expected/pg_variables.out +++ b/expected/pg_variables.out @@ -773,8 +773,8 @@ CLOSE r1_cur; COMMIT; -- warning RESET client_min_messages; -- Clean memory after unsuccessful creation of a variable -SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); -- fail -ERROR: could not identify a hash function for type unknown +SELECT pgv_insert('vars4', 'r1', row (('str1'::text, 'str1'::text))); -- fail +ERROR: could not identify a hash function for type record SELECT package FROM pgv_stats() WHERE package = 'vars4'; package --------- @@ -954,20 +954,24 @@ SELECT pgv_select('vars', 'r1'); (1,str1,str2) (1 row) -SELECT pgv_insert('vars', 'r2', row(1, 'str1')); +SELECT pgv_insert('vars', 'r2', row(1, 'str1')); -- ok, UNKNOWNOID of 'str1' converts to TEXTOID + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r2', foo) FROM foo; -- ok pgv_insert ------------ (1 row) -SELECT pgv_insert('vars', 'r2', foo) FROM foo; -ERROR: new record attribute type for attribute number 2 differs from variable "r2" structure. -HINT: You may need explicit type casts. SELECT pgv_select('vars', 'r2'); pgv_select ------------ (1,str1) -(1 row) + (0,str00) +(2 rows) SELECT pgv_insert('vars', 'r3', row(1, 'str1'::text)); pgv_insert @@ -975,7 +979,7 @@ SELECT pgv_insert('vars', 'r3', row(1, 'str1'::text)); (1 row) -SELECT pgv_insert('vars', 'r3', foo) FROM foo; +SELECT pgv_insert('vars', 'r3', foo) FROM foo; -- ok, no conversions pgv_insert ------------ @@ -988,3 +992,37 @@ SELECT pgv_select('vars', 'r3'); (0,str00) (2 rows) +SELECT pgv_insert('vars', 'r4', row(1, 2::int)); + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r4', row(0, 'str1')); -- fail, UNKNOWNOID of 'str1' can't be converted to int +ERROR: new record attribute type for attribute number 2 differs from variable "r4" structure. +HINT: You may need explicit type casts. +SELECT pgv_select('vars', 'r4'); + pgv_select +------------ + (1,2) +(1 row) + +SELECT pgv_insert('vars', 'r5', foo) FROM foo; -- types: int, text + pgv_insert +------------ + +(1 row) + +SELECT pgv_insert('vars', 'r5', row(1, 'str1')); -- ok, UNKNOWNOID of 'str1' converts to TEXTOID + pgv_insert +------------ + +(1 row) + +SELECT pgv_select('vars', 'r5'); + pgv_select +------------ + (1,str1) + (0,str00) +(2 rows) + diff --git a/expected/pg_variables_trans.out b/expected/pg_variables_trans.out index 6cede44..09f56c8 100644 --- a/expected/pg_variables_trans.out +++ b/expected/pg_variables_trans.out @@ -1858,8 +1858,8 @@ SELECT pgv_insert('package', 'errs',row(1), true); (1 row) -- Variable should not exists in case when error occurs during creation -SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); -ERROR: could not identify a hash function for type unknown +SELECT pgv_insert('vars4', 'r1', row (('str1'::text, 'str1'::text))); +ERROR: could not identify a hash function for type record SELECT pgv_select('vars4', 'r1', 0); ERROR: unrecognized package "vars4" -- If variable created and removed in same transaction level, diff --git a/pg_variables.c b/pg_variables.c index bcd0e21..f658541 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -114,6 +114,10 @@ do { \ } while(0) #endif /* PG_VERSION_NUM */ +/* User controlled GUCs */ +bool convert_unknownoid_guc; +bool convert_unknownoid; + static HTAB *packagesHash = NULL; static MemoryContext ModuleContext = NULL; @@ -701,6 +705,14 @@ variable_insert(PG_FUNCTION_ARGS) /* * This is the first record for the var_name. Initialize record. */ + /* Convert UNKNOWNOID to TEXTOID if needed + * tupdesc may be changed + */ + if (convert_unknownoid) + { + coerce_unknown_first_record(&tupdesc, &rec); + } + init_record(record, tupdesc, variable); variable->is_deleted = false; } @@ -709,8 +721,11 @@ variable_insert(PG_FUNCTION_ARGS) /* * We need to check attributes of the new row if this is a transient * record type or if last record has different id. + * Also we convert UNKNOWNOID to TEXTOID if needed. + * tupdesc may be changed */ - check_attributes(variable, tupdesc); + check_attributes(variable, &rec, tupdesc); + } insert_record(variable, rec); @@ -791,7 +806,11 @@ variable_update(PG_FUNCTION_ARGS) tupTypmod = HeapTupleHeaderGetTypMod(rec); tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); - check_attributes(variable, tupdesc); + /* + * Convert UNKNOWNOID to TEXTOID if needed + * tupdesc may be changed + */ + check_attributes(variable, &rec, tupdesc); ReleaseTupleDesc(tupdesc); res = update_record(variable, rec); @@ -2622,6 +2641,17 @@ freeStatsLists(void) void _PG_init(void) { + DefineCustomBoolVariable("pg_variables.convert_unknownoid", + "Use \'TEXT\' format for all values of \'UNKNOWNOID\', default is true.", + NULL, + &convert_unknownoid, + true, + PGC_USERSET, + 0, /* FLAGS??? */ + NULL, + NULL, + NULL); + RegisterXactCallback(pgvTransCallback, NULL); RegisterSubXactCallback(pgvSubTransCallback, NULL); diff --git a/pg_variables.h b/pg_variables.h index b08faa6..52d8c84 100644 --- a/pg_variables.h +++ b/pg_variables.h @@ -16,6 +16,7 @@ #include "access/tupdesc.h" #include "datatype/timestamp.h" #include "utils/date.h" +#include "utils/guc.h" #include "utils/hsearch.h" #include "utils/numeric.h" #include "utils/jsonb.h" @@ -155,8 +156,12 @@ typedef struct ChangesStackNode MemoryContext ctx; } ChangesStackNode; +/* pg_variables.c */ +extern bool convert_unknownoid; + extern void init_record(RecordVar *record, TupleDesc tupdesc, Variable *variable); -extern void check_attributes(Variable *variable, TupleDesc tupdesc); +extern void check_attributes(Variable *variable, HeapTupleHeader *rec, TupleDesc tupdesc); +extern void coerce_unknown_first_record(TupleDesc *tupdesc, HeapTupleHeader * rec); extern void check_record_key(Variable *variable, Oid typid); extern void insert_record(Variable *variable, HeapTupleHeader tupleHeader); diff --git a/pg_variables_record.c b/pg_variables_record.c index 3d7ca18..b067758 100644 --- a/pg_variables_record.c +++ b/pg_variables_record.c @@ -25,8 +25,11 @@ #include "catalog/pg_collation.h" #include "catalog/pg_type.h" +#include "parser/parse_type.h" #include "utils/builtins.h" #include "utils/datum.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" #include "utils/memutils.h" #include "utils/typcache.h" @@ -172,14 +175,118 @@ init_record(RecordVar *record, TupleDesc tupdesc, Variable *variable) MemoryContextSwitchTo(oldcxt); } +/* Check if any attributes of type UNKNOWNOID are in given tupdesc */ +static int +is_unknownoid_in_tupdesc(TupleDesc tupdesc) +{ + int i = 0; + for (i = 0; i < tupdesc->natts; i++) + { + Form_pg_attribute attr = GetTupleDescAttr(tupdesc, i); + + if (attr->atttypid == UNKNOWNOID) + return true; + + } + return false; +} + +/* Replace all attributes of type UNKNOWNOID to TEXTOID in given tupdesc */ +static void +coerce_unknown_rewrite_tupdesc(TupleDesc old_tupdesc, TupleDesc *return_tupdesc) +{ + int i; + + (*return_tupdesc) = CreateTupleDescCopy(old_tupdesc); + + for (i = 0; i < old_tupdesc->natts; i++) + { + Form_pg_attribute attr = GetTupleDescAttr(old_tupdesc, i); + + if (attr->atttypid == UNKNOWNOID) + { + FormData_pg_attribute new_attr = *attr; + + new_attr.atttypid = TEXTOID; + new_attr.attlen = -1; + new_attr.atttypmod = -1; + memcpy(TupleDescAttr((*return_tupdesc), i), &new_attr, sizeof(FormData_pg_attribute)); + } + } +} + +/* + * Deform tuple with old_tupdesc, coerce values of type UNKNOWNOID to TEXTOID, form tuple with new_tupdesc. + * new_tupdesc must have the same attributes as old_tupdesc except such of types UNKNOWNOID -- they must be of TEXTOID type + */ +static void +reconstruct_tuple(TupleDesc old_tupdesc, TupleDesc new_tupdesc, HeapTupleHeader *rec) +{ + HeapTupleData tuple; + HeapTuple newtup; + Datum *values = (Datum*)palloc(old_tupdesc->natts * sizeof(Datum)); + bool *isnull = (bool*)palloc(old_tupdesc->natts * sizeof(bool)); + Oid baseTypeId = UNKNOWNOID; + int32 baseTypeMod = -1; + int32 inputTypeMod = -1; + Type baseType = NULL; + int i; + + baseTypeId = getBaseTypeAndTypmod(TEXTOID, &baseTypeMod); + baseType = typeidType(baseTypeId); + /* Build a temporary HeapTuple control structure */ + tuple.t_len = HeapTupleHeaderGetDatumLength(*rec); + tuple.t_data = *rec; + heap_deform_tuple(&tuple, old_tupdesc, values, isnull); + + for (i = 0; i < old_tupdesc->natts; i++) + { + Form_pg_attribute attr = GetTupleDescAttr(old_tupdesc, i); + + if (attr->atttypid == UNKNOWNOID) + { + values[i] = stringTypeDatum(baseType, + DatumGetCString(values[i]), + inputTypeMod); + } + } + + newtup = heap_form_tuple(new_tupdesc, values, isnull); + (*rec) = newtup->t_data; + pfree(isnull); + pfree(values); + ReleaseSysCache(baseType); +} + +/* + * Used in pg_variables.c insert_record for coercing types in first record in variable. + * If there are UNKNOWNOIDs in tupdesc, rewrites it and reconstructs tuple with new tupdesc. + * Replaces given tupdesc with the new one. + */ +void +coerce_unknown_first_record(TupleDesc *tupdesc, HeapTupleHeader *rec) +{ + TupleDesc new_tupdesc = NULL; + + if (!is_unknownoid_in_tupdesc(*tupdesc)) + return; + + coerce_unknown_rewrite_tupdesc(*tupdesc, &new_tupdesc); + reconstruct_tuple(*tupdesc, new_tupdesc, rec); + + ReleaseTupleDesc(*tupdesc); + (*tupdesc) = new_tupdesc; +} + /* * New record structure should be the same as the first record. */ void -check_attributes(Variable *variable, TupleDesc tupdesc) +check_attributes(Variable *variable, HeapTupleHeader *rec, TupleDesc tupdesc) { int i; RecordVar *record; + bool unknowns = false; Assert(variable->typid == RECORDOID); @@ -198,6 +305,16 @@ check_attributes(Variable *variable, TupleDesc tupdesc) Form_pg_attribute attr1 = GetTupleDescAttr(record->tupdesc, i), attr2 = GetTupleDescAttr(tupdesc, i); + /* + * For the sake of convenience, we consider all the unknown types are to be + * a text type. + */ + if (convert_unknownoid && (attr1->atttypid == TEXTOID) && (attr2->atttypid == UNKNOWNOID)) + { + unknowns = true; + continue; + } + if ((attr1->atttypid != attr2->atttypid) || (attr1->attndims != attr2->attndims) || (attr1->atttypmod != attr2->atttypmod)) @@ -208,6 +325,9 @@ check_attributes(Variable *variable, TupleDesc tupdesc) i + 1, GetName(variable)), errhint("You may need explicit type casts."))); } + + if (unknowns) + reconstruct_tuple(tupdesc, record->tupdesc, rec); } /* diff --git a/sql/pg_variables.sql b/sql/pg_variables.sql index bad7976..4b9a3d2 100644 --- a/sql/pg_variables.sql +++ b/sql/pg_variables.sql @@ -222,7 +222,7 @@ COMMIT; -- warning RESET client_min_messages; -- Clean memory after unsuccessful creation of a variable -SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); -- fail +SELECT pgv_insert('vars4', 'r1', row (('str1'::text, 'str1'::text))); -- fail SELECT package FROM pgv_stats() WHERE package = 'vars4'; -- Remove package if it is empty @@ -268,10 +268,18 @@ SELECT pgv_select('vars', 'r1'); SELECT pgv_insert('vars', 'r1', foo) FROM foo; SELECT pgv_select('vars', 'r1'); -SELECT pgv_insert('vars', 'r2', row(1, 'str1')); -SELECT pgv_insert('vars', 'r2', foo) FROM foo; +SELECT pgv_insert('vars', 'r2', row(1, 'str1')); -- ok, UNKNOWNOID of 'str1' converts to TEXTOID +SELECT pgv_insert('vars', 'r2', foo) FROM foo; -- ok SELECT pgv_select('vars', 'r2'); SELECT pgv_insert('vars', 'r3', row(1, 'str1'::text)); -SELECT pgv_insert('vars', 'r3', foo) FROM foo; +SELECT pgv_insert('vars', 'r3', foo) FROM foo; -- ok, no conversions SELECT pgv_select('vars', 'r3'); + +SELECT pgv_insert('vars', 'r4', row(1, 2::int)); +SELECT pgv_insert('vars', 'r4', row(0, 'str1')); -- fail, UNKNOWNOID of 'str1' can't be converted to int +SELECT pgv_select('vars', 'r4'); + +SELECT pgv_insert('vars', 'r5', foo) FROM foo; -- types: int, text +SELECT pgv_insert('vars', 'r5', row(1, 'str1')); -- ok, UNKNOWNOID of 'str1' converts to TEXTOID +SELECT pgv_select('vars', 'r5'); diff --git a/sql/pg_variables_trans.sql b/sql/pg_variables_trans.sql index 7deef59..ae69df7 100644 --- a/sql/pg_variables_trans.sql +++ b/sql/pg_variables_trans.sql @@ -470,7 +470,7 @@ FROM generate_series(1,5) AS gs(n) WHERE 1.0/(n-3)<>0; SELECT pgv_insert('package', 'errs',row(1), true); -- Variable should not exists in case when error occurs during creation -SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); +SELECT pgv_insert('vars4', 'r1', row (('str1'::text, 'str1'::text))); SELECT pgv_select('vars4', 'r1', 0); -- If variable created and removed in same transaction level, From b317eb0cc727a6fb834073cd384e4d7d72fdfc96 Mon Sep 17 00:00:00 2001 From: Sofia Kopikova Date: Tue, 22 Mar 2022 12:39:01 +0300 Subject: [PATCH 28/46] update copyrigth notices --- LICENSE | 2 +- pg_variables.c | 2 +- pg_variables.h | 2 +- pg_variables_record.c | 2 +- run_tests.sh | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LICENSE b/LICENSE index f340ae8..9c8fe9d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ pg_variables is released under the PostgreSQL License, a liberal Open Source license, similar to the BSD or MIT licenses. -Copyright (c) 2016-2018, Postgres Professional +Copyright (c) 2016-2022, Postgres Professional Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/pg_variables.c b/pg_variables.c index 837f35e..b1d1b47 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -3,7 +3,7 @@ * pg_variables.c * Functions, which get or set variables values * - * Copyright (c) 2015-2021, Postgres Professional + * Copyright (c) 2015-2022, Postgres Professional * *------------------------------------------------------------------------- */ diff --git a/pg_variables.h b/pg_variables.h index aca7e93..afa9b22 100644 --- a/pg_variables.h +++ b/pg_variables.h @@ -3,7 +3,7 @@ * pg_variables.c * exported definitions for pg_variables.c * - * Copyright (c) 2015-2016, Postgres Professional + * Copyright (c) 2015-2022, Postgres Professional * *------------------------------------------------------------------------- */ diff --git a/pg_variables_record.c b/pg_variables_record.c index 1aeeadd..dadb14f 100644 --- a/pg_variables_record.c +++ b/pg_variables_record.c @@ -3,7 +3,7 @@ * pg_variables_record.c * Functions to work with record types * - * Copyright (c) 2015-2016, Postgres Professional + * Copyright (c) 2015-2022, Postgres Professional * *------------------------------------------------------------------------- */ diff --git a/run_tests.sh b/run_tests.sh index 2574328..2e63dad 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # -# Copyright (c) 2018, Postgres Professional +# Copyright (c) 2018-2022, Postgres Professional # # supported levels: # * standard From 0806ab15b5f549dfbd8f686dfcbbf6b99601c686 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Tue, 31 May 2022 14:20:27 +0300 Subject: [PATCH 29/46] [PGPRO-5833] Changes for tests with nightmare level (travis-ci) --- run_tests.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/run_tests.sh b/run_tests.sh index 2574328..ad0cd67 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -43,7 +43,7 @@ if [ "$LEVEL" = "hardcore" ] || \ # enable additional options ./configure \ CFLAGS='-O0 -ggdb3 -fno-omit-frame-pointer' \ - --enable-cassert \ + --enable-cassert --enable-debug \ --prefix=$CUSTOM_PG_BIN \ --quiet @@ -100,6 +100,7 @@ if [ "$LEVEL" = "nightmare" ]; then --time-stamp=yes \ --track-origins=yes \ --trace-children=yes \ + --trace-children-skip="/bin/*,/usr/bin/*,/lib/*" \ --gen-suppressions=all \ --suppressions=$CUSTOM_PG_SRC/src/tools/valgrind.supp \ --suppressions=$PWD/valgrind.supp \ From d4786bf45122acfeb8da8661a0ff0ce6e1f426dc Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Tue, 31 May 2022 17:06:49 +0300 Subject: [PATCH 30/46] [PGPRO-5833] Added tests for v14 + tests with nightmare level for v11, v12 --- .travis.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6f7474d..9b62198 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,18 +20,19 @@ notifications: on_failure: always env: + - PG_VERSION=14 LEVEL=nightmare + - PG_VERSION=14 LEVEL=hardcore + - PG_VERSION=14 - PG_VERSION=13 LEVEL=nightmare - PG_VERSION=13 LEVEL=hardcore - PG_VERSION=13 - # - PG_VERSION=12 LEVEL=nightmare + - PG_VERSION=12 LEVEL=nightmare - PG_VERSION=12 LEVEL=hardcore - PG_VERSION=12 - # - PG_VERSION=11 LEVEL=nightmare + - PG_VERSION=11 LEVEL=nightmare - PG_VERSION=11 LEVEL=hardcore - PG_VERSION=11 - PG_VERSION=10 - - PG_VERSION=9.6 - - PG_VERSION=9.5 # XXX: consider fixing nightmare mode matrix: @@ -39,3 +40,4 @@ matrix: - env: PG_VERSION=11 LEVEL=nightmare - env: PG_VERSION=12 LEVEL=nightmare - env: PG_VERSION=13 LEVEL=nightmare + - env: PG_VERSION=14 LEVEL=nightmare From 9f9466c2b9193133446851b1f4b2b5b192d8f0e0 Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Fri, 9 Sep 2022 17:22:21 +0300 Subject: [PATCH 31/46] Remove _PG_fini call Due to upstream commit ab02d702, _PG_fini was removed. To be consistent, we remove this particular call too. --- pg_variables.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pg_variables.c b/pg_variables.c index b1d1b47..5c52c79 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -47,7 +47,9 @@ PG_FUNCTION_INFO_V1(get_packages_and_variables); PG_FUNCTION_INFO_V1(get_packages_stats); extern void _PG_init(void); +#if PG_VERSION_NUM < 150000 extern void _PG_fini(void); +#endif static void ensurePackagesHashExists(void); static void getKeyFromName(text *name, char *key); @@ -2959,6 +2961,7 @@ _PG_init(void) ExecutorEnd_hook = variable_ExecutorEnd; } +#if PG_VERSION_NUM < 150000 /* * Unregister callback function when module unloads */ @@ -2969,3 +2972,4 @@ _PG_fini(void) UnregisterSubXactCallback(pgvSubTransCallback, NULL); ExecutorEnd_hook = prev_ExecutorEnd; } +#endif From 9c3d02817d85ce676c4bc43c5574d11b297ad11a Mon Sep 17 00:00:00 2001 From: Marina Polyakova Date: Wed, 14 Dec 2022 11:41:58 +0300 Subject: [PATCH 32/46] Remove AssertArg See the commit b1099eca8f38ff5cfaf0901bb91cb6a22f909bc6 (Remove AssertArg and AssertState) in PostgreSQL 16. --- pg_variables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pg_variables.c b/pg_variables.c index 5c52c79..9c571d7 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -1582,7 +1582,7 @@ getMemoryTotalSpace(MemoryContext context, int level, Size *totalspace) MemoryContext child; MemoryContextCounters totals; - AssertArg(MemoryContextIsValid(context)); + Assert(MemoryContextIsValid(context)); /* Examine the context itself */ memset(&totals, 0, sizeof(totals)); From ffdf2427b7914890e041d1ec52c1c85e84e9e23a Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Mon, 19 Dec 2022 11:47:25 +0300 Subject: [PATCH 33/46] Add support for PG15 in travis --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9b62198..228302a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,9 @@ notifications: on_failure: always env: + - PG_VERSION=15 LEVEL=nightmare + - PG_VERSION=15 LEVEL=hardcore + - PG_VERSION=15 - PG_VERSION=14 LEVEL=nightmare - PG_VERSION=14 LEVEL=hardcore - PG_VERSION=14 @@ -41,3 +44,4 @@ matrix: - env: PG_VERSION=12 LEVEL=nightmare - env: PG_VERSION=13 LEVEL=nightmare - env: PG_VERSION=14 LEVEL=nightmare + - env: PG_VERSION=15 LEVEL=nightmare From 43aac50a9314466ff91857294fd5584b1aa11f7b Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Mon, 26 Dec 2022 19:34:27 +0300 Subject: [PATCH 34/46] [PGPRO-6577] Remove obsolete test results (incl. v10) Tags: pg_variables --- .travis.yml | 1 - expected/pg_variables_atx_1.out | 465 ------------------------------ expected/pg_variables_atx_2.out | 497 -------------------------------- expected/pg_variables_atx_3.out | 497 -------------------------------- expected/pg_variables_atx_4.out | 497 -------------------------------- 5 files changed, 1957 deletions(-) delete mode 100644 expected/pg_variables_atx_1.out delete mode 100644 expected/pg_variables_atx_2.out delete mode 100644 expected/pg_variables_atx_3.out delete mode 100644 expected/pg_variables_atx_4.out diff --git a/.travis.yml b/.travis.yml index 228302a..45189e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,6 @@ env: - PG_VERSION=11 LEVEL=nightmare - PG_VERSION=11 LEVEL=hardcore - PG_VERSION=11 - - PG_VERSION=10 # XXX: consider fixing nightmare mode matrix: diff --git a/expected/pg_variables_atx_1.out b/expected/pg_variables_atx_1.out deleted file mode 100644 index b5d8a07..0000000 --- a/expected/pg_variables_atx_1.out +++ /dev/null @@ -1,465 +0,0 @@ -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------- --- Non-transactional variables ------------------------------- -select pgv_set('vars', 'int1', 101); - pgv_set ---------- - -(1 row) - -begin; - select pgv_set('vars', 'int2', 102); - pgv_set ---------- - -(1 row) - - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - select pgv_set('vars', 'int3', 103); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 101, 102, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars', 'int1', 1001); -ERROR: current transaction is aborted, commands ignored until end of transaction block - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ --- 1001, 102, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars', 'int2', 1002); -ERROR: current transaction is aborted, commands ignored until end of transaction block - commit; - commit; -WARNING: there is no transaction in progress --- 1001, 1002, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); -ERROR: unrecognized variable "int3" - select pgv_set('vars', 'int3', 1003); - pgv_set ---------- - -(1 row) - -rollback; -WARNING: there is no transaction in progress --- 1001, 1002, 1003: -select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 101 | 102 | 1003 -(1 row) - --- vars:int1, vars:int2, vars:int3: -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - vars | int1 | f - vars | int2 | f - vars | int3 | f -(3 rows) - -select pgv_free(); - pgv_free ----------- - -(1 row) - --------------------------- --- Transactional variables --------------------------- -select pgv_set('vars', 'int1', 101, true); - pgv_set ---------- - -(1 row) - -begin; - select pgv_set('vars', 'int2', 102, true); - pgv_set ---------- - -(1 row) - - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - select pgv_set('vars', 'int3', 103, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 103: - select pgv_get('vars', 'int3', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - select pgv_set('vars', 'int2', 1002, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 1002: - select pgv_get('vars', 'int2', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - commit; --- 103: - select pgv_get('vars', 'int3', null::int); -ERROR: unrecognized variable "int3" - commit; -WARNING: there is no transaction in progress - select pgv_set('vars', 'int1', 1001, true); - pgv_set ---------- - -(1 row) - --- 1001: - select pgv_get('vars', 'int1', null::int); - pgv_get ---------- - 1001 -(1 row) - --- 102: - select pgv_get('vars', 'int2', null::int); -ERROR: unrecognized variable "int2" -rollback; -WARNING: there is no transaction in progress --- 101: -select pgv_get('vars', 'int1', null::int); - pgv_get ---------- - 1001 -(1 row) - --- vars:int1: -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - vars | int1 | t -(1 row) - -select pgv_free(); - pgv_free ----------- - -(1 row) - ----------- --- Cursors ----------- -select pgv_insert('test', 'x', row (1::int, 2::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'x', row (2::int, 3::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'x', row (3::int, 4::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (10::int, 20::int), true); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (20::int, 30::int), true); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (30::int, 40::int), true); - pgv_insert ------------- - -(1 row) - -begin; - declare r1_cur cursor for select pgv_select('test', 'x'); - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - select pgv_insert('test', 'z', row (11::int, 22::int), false); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_insert('test', 'z', row (22::int, 33::int), false); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_insert('test', 'z', row (33::int, 44::int), false); -ERROR: current transaction is aborted, commands ignored until end of transaction block - declare r11_cur cursor for select pgv_select('test', 'x'); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- (1,2),(2,3): - fetch 2 in r11_cur; -ERROR: current transaction is aborted, commands ignored until end of transaction block - declare r2_cur cursor for select pgv_select('test', 'y'); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- correct error: unrecognized variable "y" - fetch 2 in r2_cur; -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback; - rollback; -WARNING: there is no transaction in progress - rollback; -WARNING: there is no transaction in progress - rollback; -WARNING: there is no transaction in progress - rollback; -WARNING: there is no transaction in progress - declare r2_cur cursor for select pgv_select('test', 'y'); -ERROR: DECLARE CURSOR can only be used in transaction blocks - declare r3_cur cursor for select pgv_select('test', 'z'); -ERROR: DECLARE CURSOR can only be used in transaction blocks --- (1,2),(2,3): - fetch 2 in r1_cur; -ERROR: cursor "r1_cur" does not exist --- (10,20),(20,30): - fetch 2 in r2_cur; -ERROR: cursor "r2_cur" does not exist --- (11,22),(22,33): - fetch 2 in r3_cur; -ERROR: cursor "r3_cur" does not exist -rollback; -WARNING: there is no transaction in progress -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------- --- Savepoint: rollback in main transaction ------------------------------------------- -begin; - select pgv_set('vars', 'trans_int', 101, true); - pgv_set ---------- - -(1 row) - --- 101: - select pgv_get('vars', 'trans_int', null::int); - pgv_get ---------- - 101 -(1 row) - - savepoint sp1; - select pgv_set('vars', 'trans_int', 102, true); - pgv_set ---------- - -(1 row) - --- 102: - select pgv_get('vars', 'trans_int', null::int); - pgv_get ---------- - 102 -(1 row) - - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - select pgv_set('vars', 'trans_int', 103, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 103: - select pgv_get('vars', 'trans_int', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - commit; --- 102: - select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" - rollback to sp1; -ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks -commit; -WARNING: there is no transaction in progress --- 101: -select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------------- --- Savepoint: rollback in autonomous transaction ------------------------------------------------- -begin; - select pgv_set('vars', 'trans_int', 1, true); - pgv_set ---------- - -(1 row) - - savepoint sp1; - select pgv_set('vars', 'trans_int', 100, true); - pgv_set ---------- - -(1 row) - - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - select pgv_set('vars1', 'int1', 2); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 3, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - savepoint sp2; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 4, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 2 - select pgv_get('vars1', 'int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 4 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback to sp2; -ERROR: no such savepoint --- 3 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- vars1:int1, vars1:trans_int1: - select * from pgv_list() order by package, name; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int2', 4, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int3', 5, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'int2', 3); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback; - commit; -WARNING: there is no transaction in progress - rollback to sp1; -ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks --- 1 - select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" --- 2 - select pgv_get('vars1', 'int1', null::int); -ERROR: unrecognized package "vars1" --- 3 - select pgv_get('vars1', 'int2', null::int); -ERROR: unrecognized package "vars1" --- vars:trans_int, vars1:int1, vars1:int2: - select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -commit; -WARNING: there is no transaction in progress -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------------------------- --- Sample with (subxact inside ATX) == (subxact outside ATX) ------------------------------------------------------------- -select pgv_set('vars1', 'int1', 0); - pgv_set ---------- - -(1 row) - -select pgv_set('vars1', 'trans_int1', 0, true); - pgv_set ---------- - -(1 row) - -begin; - begin autonomous; -ERROR: syntax error at or near "autonomous" -LINE 1: begin autonomous; - ^ - select pgv_set('vars1', 'int1', 1); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 2, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - savepoint sp2; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 3, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback to sp2; -ERROR: no such savepoint --- 2 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - commit; -rollback; -WARNING: there is no transaction in progress --- vars1:int1, vars1:trans_int1 -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------------+------------------ - vars1 | int1 | f - vars1 | trans_int1 | t -(2 rows) - --- 1 -select pgv_get('vars1', 'int1', null::int); - pgv_get ---------- - 0 -(1 row) - --- 0 -select pgv_get('vars1', 'trans_int1', null::int); - pgv_get ---------- - 0 -(1 row) - -select pgv_free(); - pgv_free ----------- - -(1 row) - diff --git a/expected/pg_variables_atx_2.out b/expected/pg_variables_atx_2.out deleted file mode 100644 index c6f44a7..0000000 --- a/expected/pg_variables_atx_2.out +++ /dev/null @@ -1,497 +0,0 @@ -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------- --- Non-transactional variables ------------------------------- -select pgv_set('vars', 'int1', 101); - pgv_set ---------- - -(1 row) - -begin; - select pgv_set('vars', 'int2', 102); - pgv_set ---------- - -(1 row) - - begin autonomous; - select pgv_set('vars', 'int3', 103); - pgv_set ---------- - -(1 row) - --- 101, 102, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 101 | 102 | 103 -(1 row) - - select pgv_set('vars', 'int1', 1001); - pgv_set ---------- - -(1 row) - - begin autonomous; --- 1001, 102, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 1001 | 102 | 103 -(1 row) - - select pgv_set('vars', 'int2', 1002); - pgv_set ---------- - -(1 row) - - commit; - commit; --- 1001, 1002, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 1001 | 1002 | 103 -(1 row) - - select pgv_set('vars', 'int3', 1003); - pgv_set ---------- - -(1 row) - -rollback; --- 1001, 1002, 1003: -select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 1001 | 1002 | 1003 -(1 row) - --- vars:int1, vars:int2, vars:int3: -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - vars | int1 | f - vars | int2 | f - vars | int3 | f -(3 rows) - -select pgv_free(); - pgv_free ----------- - -(1 row) - --------------------------- --- Transactional variables --------------------------- -select pgv_set('vars', 'int1', 101, true); - pgv_set ---------- - -(1 row) - -begin; - select pgv_set('vars', 'int2', 102, true); - pgv_set ---------- - -(1 row) - - begin autonomous; - select pgv_set('vars', 'int3', 103, true); - pgv_set ---------- - -(1 row) - --- 103: - select pgv_get('vars', 'int3', null::int); - pgv_get ---------- - 103 -(1 row) - - begin autonomous; - select pgv_set('vars', 'int2', 1002, true); - pgv_set ---------- - -(1 row) - --- 1002: - select pgv_get('vars', 'int2', null::int); - pgv_get ---------- - 1002 -(1 row) - - commit; --- 103: - select pgv_get('vars', 'int3', null::int); - pgv_get ---------- - 103 -(1 row) - - commit; - select pgv_set('vars', 'int1', 1001, true); - pgv_set ---------- - -(1 row) - --- 1001: - select pgv_get('vars', 'int1', null::int); - pgv_get ---------- - 1001 -(1 row) - --- 102: - select pgv_get('vars', 'int2', null::int); - pgv_get ---------- - 102 -(1 row) - -rollback; --- 101: -select pgv_get('vars', 'int1', null::int); - pgv_get ---------- - 101 -(1 row) - --- vars:int1: -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - vars | int1 | t -(1 row) - -select pgv_free(); - pgv_free ----------- - -(1 row) - ----------- --- Cursors ----------- -select pgv_insert('test', 'x', row (1::int, 2::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'x', row (2::int, 3::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'x', row (3::int, 4::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (10::int, 20::int), true); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (20::int, 30::int), true); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (30::int, 40::int), true); - pgv_insert ------------- - -(1 row) - -begin; - declare r1_cur cursor for select pgv_select('test', 'x'); - begin autonomous; - begin autonomous; - begin autonomous; - begin autonomous; - begin autonomous; - select pgv_insert('test', 'z', row (11::int, 22::int), false); - pgv_insert ------------- - -(1 row) - - select pgv_insert('test', 'z', row (22::int, 33::int), false); - pgv_insert ------------- - -(1 row) - - select pgv_insert('test', 'z', row (33::int, 44::int), false); - pgv_insert ------------- - -(1 row) - - declare r11_cur cursor for select pgv_select('test', 'x'); --- (1,2),(2,3): - fetch 2 in r11_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - - declare r2_cur cursor for select pgv_select('test', 'y'); --- correct error: unrecognized variable "y" - fetch 2 in r2_cur; -ERROR: unrecognized variable "y" - rollback; - rollback; - rollback; - rollback; - rollback; - declare r2_cur cursor for select pgv_select('test', 'y'); - declare r3_cur cursor for select pgv_select('test', 'z'); --- (1,2),(2,3): - fetch 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - --- (10,20),(20,30): - fetch 2 in r2_cur; - pgv_select ------------- - (10,20) - (20,30) -(2 rows) - --- (11,22),(22,33): - fetch 2 in r3_cur; - pgv_select ------------- - (11,22) - (22,33) -(2 rows) - -rollback; -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------- --- Savepoint: rollback in main transaction ------------------------------------------- -begin; - select pgv_set('vars', 'trans_int', 101, true); - pgv_set ---------- - -(1 row) - --- 101: - select pgv_get('vars', 'trans_int', null::int); - pgv_get ---------- - 101 -(1 row) - - savepoint sp1; - select pgv_set('vars', 'trans_int', 102, true); - pgv_set ---------- - -(1 row) - --- 102: - select pgv_get('vars', 'trans_int', null::int); - pgv_get ---------- - 102 -(1 row) - - begin autonomous; -ERROR: in_memory extension is incompatible with autonomous transactions - select pgv_set('vars', 'trans_int', 103, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 103: - select pgv_get('vars', 'trans_int', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - commit; --- 102: - select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" - rollback to sp1; -ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks -commit; -WARNING: there is no transaction in progress --- 101: -select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------------- --- Savepoint: rollback in autonomous transaction ------------------------------------------------- -begin; - select pgv_set('vars', 'trans_int', 1, true); - pgv_set ---------- - -(1 row) - - savepoint sp1; - select pgv_set('vars', 'trans_int', 100, true); - pgv_set ---------- - -(1 row) - - begin autonomous; -ERROR: in_memory extension is incompatible with autonomous transactions - begin autonomous; -ERROR: in_memory extension is incompatible with autonomous transactions - select pgv_set('vars1', 'int1', 2); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 3, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - savepoint sp2; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 4, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 2 - select pgv_get('vars1', 'int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 4 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback to sp2; -ERROR: savepoint "sp2" does not exist --- 3 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- vars1:int1, vars1:trans_int1: - select * from pgv_list() order by package, name; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int2', 4, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int3', 5, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'int2', 3); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback; - commit; -WARNING: there is no transaction in progress - rollback to sp1; -ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks --- 1 - select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" --- 2 - select pgv_get('vars1', 'int1', null::int); -ERROR: unrecognized package "vars1" --- 3 - select pgv_get('vars1', 'int2', null::int); -ERROR: unrecognized package "vars1" --- vars:trans_int, vars1:int1, vars1:int2: - select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -commit; -WARNING: there is no transaction in progress -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------------------------- --- Sample with (subxact inside ATX) == (subxact outside ATX) ------------------------------------------------------------- -select pgv_set('vars1', 'int1', 0); - pgv_set ---------- - -(1 row) - -select pgv_set('vars1', 'trans_int1', 0, true); - pgv_set ---------- - -(1 row) - -begin; - begin autonomous; -ERROR: in_memory extension is incompatible with autonomous transactions - select pgv_set('vars1', 'int1', 1); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 2, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - savepoint sp2; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 3, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback to sp2; -ERROR: savepoint "sp2" does not exist --- 2 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - commit; -rollback; -WARNING: there is no transaction in progress --- vars1:int1, vars1:trans_int1 -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------------+------------------ - vars1 | int1 | f - vars1 | trans_int1 | t -(2 rows) - --- 1 -select pgv_get('vars1', 'int1', null::int); - pgv_get ---------- - 0 -(1 row) - --- 0 -select pgv_get('vars1', 'trans_int1', null::int); - pgv_get ---------- - 0 -(1 row) - -select pgv_free(); - pgv_free ----------- - -(1 row) - diff --git a/expected/pg_variables_atx_3.out b/expected/pg_variables_atx_3.out deleted file mode 100644 index ad1ae89..0000000 --- a/expected/pg_variables_atx_3.out +++ /dev/null @@ -1,497 +0,0 @@ -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------- --- Non-transactional variables ------------------------------- -select pgv_set('vars', 'int1', 101); - pgv_set ---------- - -(1 row) - -begin; - select pgv_set('vars', 'int2', 102); - pgv_set ---------- - -(1 row) - - begin autonomous; - select pgv_set('vars', 'int3', 103); - pgv_set ---------- - -(1 row) - --- 101, 102, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 101 | 102 | 103 -(1 row) - - select pgv_set('vars', 'int1', 1001); - pgv_set ---------- - -(1 row) - - begin autonomous; --- 1001, 102, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 1001 | 102 | 103 -(1 row) - - select pgv_set('vars', 'int2', 1002); - pgv_set ---------- - -(1 row) - - commit; - commit; --- 1001, 1002, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 1001 | 1002 | 103 -(1 row) - - select pgv_set('vars', 'int3', 1003); - pgv_set ---------- - -(1 row) - -rollback; --- 1001, 1002, 1003: -select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 1001 | 1002 | 1003 -(1 row) - --- vars:int1, vars:int2, vars:int3: -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - vars | int1 | f - vars | int2 | f - vars | int3 | f -(3 rows) - -select pgv_free(); - pgv_free ----------- - -(1 row) - --------------------------- --- Transactional variables --------------------------- -select pgv_set('vars', 'int1', 101, true); - pgv_set ---------- - -(1 row) - -begin; - select pgv_set('vars', 'int2', 102, true); - pgv_set ---------- - -(1 row) - - begin autonomous; - select pgv_set('vars', 'int3', 103, true); - pgv_set ---------- - -(1 row) - --- 103: - select pgv_get('vars', 'int3', null::int); - pgv_get ---------- - 103 -(1 row) - - begin autonomous; - select pgv_set('vars', 'int2', 1002, true); - pgv_set ---------- - -(1 row) - --- 1002: - select pgv_get('vars', 'int2', null::int); - pgv_get ---------- - 1002 -(1 row) - - commit; --- 103: - select pgv_get('vars', 'int3', null::int); - pgv_get ---------- - 103 -(1 row) - - commit; - select pgv_set('vars', 'int1', 1001, true); - pgv_set ---------- - -(1 row) - --- 1001: - select pgv_get('vars', 'int1', null::int); - pgv_get ---------- - 1001 -(1 row) - --- 102: - select pgv_get('vars', 'int2', null::int); - pgv_get ---------- - 102 -(1 row) - -rollback; --- 101: -select pgv_get('vars', 'int1', null::int); - pgv_get ---------- - 101 -(1 row) - --- vars:int1: -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - vars | int1 | t -(1 row) - -select pgv_free(); - pgv_free ----------- - -(1 row) - ----------- --- Cursors ----------- -select pgv_insert('test', 'x', row (1::int, 2::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'x', row (2::int, 3::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'x', row (3::int, 4::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (10::int, 20::int), true); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (20::int, 30::int), true); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (30::int, 40::int), true); - pgv_insert ------------- - -(1 row) - -begin; - declare r1_cur cursor for select pgv_select('test', 'x'); - begin autonomous; - begin autonomous; - begin autonomous; - begin autonomous; - begin autonomous; - select pgv_insert('test', 'z', row (11::int, 22::int), false); - pgv_insert ------------- - -(1 row) - - select pgv_insert('test', 'z', row (22::int, 33::int), false); - pgv_insert ------------- - -(1 row) - - select pgv_insert('test', 'z', row (33::int, 44::int), false); - pgv_insert ------------- - -(1 row) - - declare r11_cur cursor for select pgv_select('test', 'x'); --- (1,2),(2,3): - fetch 2 in r11_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - - declare r2_cur cursor for select pgv_select('test', 'y'); --- correct error: unrecognized variable "y" - fetch 2 in r2_cur; -ERROR: unrecognized variable "y" - rollback; - rollback; - rollback; - rollback; - rollback; - declare r2_cur cursor for select pgv_select('test', 'y'); - declare r3_cur cursor for select pgv_select('test', 'z'); --- (1,2),(2,3): - fetch 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - --- (10,20),(20,30): - fetch 2 in r2_cur; - pgv_select ------------- - (10,20) - (20,30) -(2 rows) - --- (11,22),(22,33): - fetch 2 in r3_cur; - pgv_select ------------- - (11,22) - (22,33) -(2 rows) - -rollback; -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------- --- Savepoint: rollback in main transaction ------------------------------------------- -begin; - select pgv_set('vars', 'trans_int', 101, true); - pgv_set ---------- - -(1 row) - --- 101: - select pgv_get('vars', 'trans_int', null::int); - pgv_get ---------- - 101 -(1 row) - - savepoint sp1; - select pgv_set('vars', 'trans_int', 102, true); - pgv_set ---------- - -(1 row) - --- 102: - select pgv_get('vars', 'trans_int', null::int); - pgv_get ---------- - 102 -(1 row) - - begin autonomous; -ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling - select pgv_set('vars', 'trans_int', 103, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 103: - select pgv_get('vars', 'trans_int', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - commit; --- 102: - select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" - rollback to sp1; -ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks -commit; -WARNING: there is no transaction in progress --- 101: -select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------------- --- Savepoint: rollback in autonomous transaction ------------------------------------------------- -begin; - select pgv_set('vars', 'trans_int', 1, true); - pgv_set ---------- - -(1 row) - - savepoint sp1; - select pgv_set('vars', 'trans_int', 100, true); - pgv_set ---------- - -(1 row) - - begin autonomous; -ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling - begin autonomous; -ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling - select pgv_set('vars1', 'int1', 2); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 3, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - savepoint sp2; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 4, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 2 - select pgv_get('vars1', 'int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 4 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback to sp2; -ERROR: no such savepoint --- 3 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- vars1:int1, vars1:trans_int1: - select * from pgv_list() order by package, name; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int2', 4, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int3', 5, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'int2', 3); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback; - commit; -WARNING: there is no transaction in progress - rollback to sp1; -ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks --- 1 - select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" --- 2 - select pgv_get('vars1', 'int1', null::int); -ERROR: unrecognized package "vars1" --- 3 - select pgv_get('vars1', 'int2', null::int); -ERROR: unrecognized package "vars1" --- vars:trans_int, vars1:int1, vars1:int2: - select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -commit; -WARNING: there is no transaction in progress -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------------------------- --- Sample with (subxact inside ATX) == (subxact outside ATX) ------------------------------------------------------------- -select pgv_set('vars1', 'int1', 0); - pgv_set ---------- - -(1 row) - -select pgv_set('vars1', 'trans_int1', 0, true); - pgv_set ---------- - -(1 row) - -begin; - begin autonomous; -ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling - select pgv_set('vars1', 'int1', 1); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 2, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - savepoint sp2; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 3, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback to sp2; -ERROR: no such savepoint --- 2 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - commit; -rollback; -WARNING: there is no transaction in progress --- vars1:int1, vars1:trans_int1 -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------------+------------------ - vars1 | int1 | f - vars1 | trans_int1 | t -(2 rows) - --- 1 -select pgv_get('vars1', 'int1', null::int); - pgv_get ---------- - 0 -(1 row) - --- 0 -select pgv_get('vars1', 'trans_int1', null::int); - pgv_get ---------- - 0 -(1 row) - -select pgv_free(); - pgv_free ----------- - -(1 row) - diff --git a/expected/pg_variables_atx_4.out b/expected/pg_variables_atx_4.out deleted file mode 100644 index 914725a..0000000 --- a/expected/pg_variables_atx_4.out +++ /dev/null @@ -1,497 +0,0 @@ -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------- --- Non-transactional variables ------------------------------- -select pgv_set('vars', 'int1', 101); - pgv_set ---------- - -(1 row) - -begin; - select pgv_set('vars', 'int2', 102); - pgv_set ---------- - -(1 row) - - begin autonomous; - select pgv_set('vars', 'int3', 103); - pgv_set ---------- - -(1 row) - --- 101, 102, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 101 | 102 | 103 -(1 row) - - select pgv_set('vars', 'int1', 1001); - pgv_set ---------- - -(1 row) - - begin autonomous; --- 1001, 102, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 1001 | 102 | 103 -(1 row) - - select pgv_set('vars', 'int2', 1002); - pgv_set ---------- - -(1 row) - - commit; - commit; --- 1001, 1002, 103: - select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 1001 | 1002 | 103 -(1 row) - - select pgv_set('vars', 'int3', 1003); - pgv_set ---------- - -(1 row) - -rollback; --- 1001, 1002, 1003: -select pgv_get('vars', 'int1', null::int), pgv_get('vars', 'int2', null::int), pgv_get('vars', 'int3', null::int); - pgv_get | pgv_get | pgv_get ----------+---------+--------- - 1001 | 1002 | 1003 -(1 row) - --- vars:int1, vars:int2, vars:int3: -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - vars | int1 | f - vars | int2 | f - vars | int3 | f -(3 rows) - -select pgv_free(); - pgv_free ----------- - -(1 row) - --------------------------- --- Transactional variables --------------------------- -select pgv_set('vars', 'int1', 101, true); - pgv_set ---------- - -(1 row) - -begin; - select pgv_set('vars', 'int2', 102, true); - pgv_set ---------- - -(1 row) - - begin autonomous; - select pgv_set('vars', 'int3', 103, true); - pgv_set ---------- - -(1 row) - --- 103: - select pgv_get('vars', 'int3', null::int); - pgv_get ---------- - 103 -(1 row) - - begin autonomous; - select pgv_set('vars', 'int2', 1002, true); - pgv_set ---------- - -(1 row) - --- 1002: - select pgv_get('vars', 'int2', null::int); - pgv_get ---------- - 1002 -(1 row) - - commit; --- 103: - select pgv_get('vars', 'int3', null::int); - pgv_get ---------- - 103 -(1 row) - - commit; - select pgv_set('vars', 'int1', 1001, true); - pgv_set ---------- - -(1 row) - --- 1001: - select pgv_get('vars', 'int1', null::int); - pgv_get ---------- - 1001 -(1 row) - --- 102: - select pgv_get('vars', 'int2', null::int); - pgv_get ---------- - 102 -(1 row) - -rollback; --- 101: -select pgv_get('vars', 'int1', null::int); - pgv_get ---------- - 101 -(1 row) - --- vars:int1: -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ - vars | int1 | t -(1 row) - -select pgv_free(); - pgv_free ----------- - -(1 row) - ----------- --- Cursors ----------- -select pgv_insert('test', 'x', row (1::int, 2::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'x', row (2::int, 3::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'x', row (3::int, 4::int), false); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (10::int, 20::int), true); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (20::int, 30::int), true); - pgv_insert ------------- - -(1 row) - -select pgv_insert('test', 'y', row (30::int, 40::int), true); - pgv_insert ------------- - -(1 row) - -begin; - declare r1_cur cursor for select pgv_select('test', 'x'); - begin autonomous; - begin autonomous; - begin autonomous; - begin autonomous; - begin autonomous; - select pgv_insert('test', 'z', row (11::int, 22::int), false); - pgv_insert ------------- - -(1 row) - - select pgv_insert('test', 'z', row (22::int, 33::int), false); - pgv_insert ------------- - -(1 row) - - select pgv_insert('test', 'z', row (33::int, 44::int), false); - pgv_insert ------------- - -(1 row) - - declare r11_cur cursor for select pgv_select('test', 'x'); --- (1,2),(2,3): - fetch 2 in r11_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - - declare r2_cur cursor for select pgv_select('test', 'y'); --- correct error: unrecognized variable "y" - fetch 2 in r2_cur; -ERROR: unrecognized variable "y" - rollback; - rollback; - rollback; - rollback; - rollback; - declare r2_cur cursor for select pgv_select('test', 'y'); - declare r3_cur cursor for select pgv_select('test', 'z'); --- (1,2),(2,3): - fetch 2 in r1_cur; - pgv_select ------------- - (1,2) - (2,3) -(2 rows) - --- (10,20),(20,30): - fetch 2 in r2_cur; - pgv_select ------------- - (10,20) - (20,30) -(2 rows) - --- (11,22),(22,33): - fetch 2 in r3_cur; - pgv_select ------------- - (11,22) - (22,33) -(2 rows) - -rollback; -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------- --- Savepoint: rollback in main transaction ------------------------------------------- -begin; - select pgv_set('vars', 'trans_int', 101, true); - pgv_set ---------- - -(1 row) - --- 101: - select pgv_get('vars', 'trans_int', null::int); - pgv_get ---------- - 101 -(1 row) - - savepoint sp1; - select pgv_set('vars', 'trans_int', 102, true); - pgv_set ---------- - -(1 row) - --- 102: - select pgv_get('vars', 'trans_int', null::int); - pgv_get ---------- - 102 -(1 row) - - begin autonomous; -ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling - select pgv_set('vars', 'trans_int', 103, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 103: - select pgv_get('vars', 'trans_int', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - commit; --- 102: - select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" - rollback to sp1; -ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks -commit; -WARNING: there is no transaction in progress --- 101: -select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------------- --- Savepoint: rollback in autonomous transaction ------------------------------------------------- -begin; - select pgv_set('vars', 'trans_int', 1, true); - pgv_set ---------- - -(1 row) - - savepoint sp1; - select pgv_set('vars', 'trans_int', 100, true); - pgv_set ---------- - -(1 row) - - begin autonomous; -ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling - begin autonomous; -ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling - select pgv_set('vars1', 'int1', 2); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 3, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - savepoint sp2; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 4, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 2 - select pgv_get('vars1', 'int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- 4 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback to sp2; -ERROR: savepoint "sp2" does not exist --- 3 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block --- vars1:int1, vars1:trans_int1: - select * from pgv_list() order by package, name; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int2', 4, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int3', 5, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'int2', 3); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback; - commit; -WARNING: there is no transaction in progress - rollback to sp1; -ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks --- 1 - select pgv_get('vars', 'trans_int', null::int); -ERROR: unrecognized package "vars" --- 2 - select pgv_get('vars1', 'int1', null::int); -ERROR: unrecognized package "vars1" --- 3 - select pgv_get('vars1', 'int2', null::int); -ERROR: unrecognized package "vars1" --- vars:trans_int, vars1:int1, vars1:int2: - select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------+------------------ -(0 rows) - -commit; -WARNING: there is no transaction in progress -select pgv_free(); - pgv_free ----------- - -(1 row) - ------------------------------------------------------------- --- Sample with (subxact inside ATX) == (subxact outside ATX) ------------------------------------------------------------- -select pgv_set('vars1', 'int1', 0); - pgv_set ---------- - -(1 row) - -select pgv_set('vars1', 'trans_int1', 0, true); - pgv_set ---------- - -(1 row) - -begin; - begin autonomous; -ERROR: Extension in_memory is not compatible with autonomous transactions and connection pooling - select pgv_set('vars1', 'int1', 1); -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 2, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - savepoint sp2; -ERROR: current transaction is aborted, commands ignored until end of transaction block - select pgv_set('vars1', 'trans_int1', 3, true); -ERROR: current transaction is aborted, commands ignored until end of transaction block - rollback to sp2; -ERROR: savepoint "sp2" does not exist --- 2 - select pgv_get('vars1', 'trans_int1', null::int); -ERROR: current transaction is aborted, commands ignored until end of transaction block - commit; -rollback; -WARNING: there is no transaction in progress --- vars1:int1, vars1:trans_int1 -select * from pgv_list() order by package, name; - package | name | is_transactional ----------+------------+------------------ - vars1 | int1 | f - vars1 | trans_int1 | t -(2 rows) - --- 1 -select pgv_get('vars1', 'int1', null::int); - pgv_get ---------- - 0 -(1 row) - --- 0 -select pgv_get('vars1', 'trans_int1', null::int); - pgv_get ---------- - 0 -(1 row) - -select pgv_free(); - pgv_free ----------- - -(1 row) - From ff47670e0499dcad08e78392c5a38b53b7a6e118 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Fri, 30 Dec 2022 04:21:27 +0300 Subject: [PATCH 35/46] [PGPRO-7614] Fix conflict between atx and pgv_free() Tags: pg_variables, atx --- .travis.yml | 1 - Makefile | 3 +- expected/pg_variables_atx_pkg.out | 274 +++++++++++++++++++++++++ expected/pg_variables_atx_pkg_1.out | 306 ++++++++++++++++++++++++++++ pg_variables.c | 30 +++ sql/pg_variables_atx_pkg.sql | 135 ++++++++++++ 6 files changed, 747 insertions(+), 2 deletions(-) create mode 100644 expected/pg_variables_atx_pkg.out create mode 100644 expected/pg_variables_atx_pkg_1.out create mode 100644 sql/pg_variables_atx_pkg.sql diff --git a/.travis.yml b/.travis.yml index 228302a..45189e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,6 @@ env: - PG_VERSION=11 LEVEL=nightmare - PG_VERSION=11 LEVEL=hardcore - PG_VERSION=11 - - PG_VERSION=10 # XXX: consider fixing nightmare mode matrix: diff --git a/Makefile b/Makefile index f95c39f..7253e93 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,8 @@ DATA_built = $(EXTENSION)--$(EXTVERSION).sql PGFILEDESC = "pg_variables - sessional variables" -REGRESS = pg_variables pg_variables_any pg_variables_trans pg_variables_atx +REGRESS = pg_variables pg_variables_any pg_variables_trans pg_variables_atx \ + pg_variables_atx_pkg ifdef USE_PGXS PG_CONFIG = pg_config diff --git a/expected/pg_variables_atx_pkg.out b/expected/pg_variables_atx_pkg.out new file mode 100644 index 0000000..a95e180 --- /dev/null +++ b/expected/pg_variables_atx_pkg.out @@ -0,0 +1,274 @@ +-- +-- PGPRO-7614: function pgv_free() inside autonomous transaction +-- +select pgv_free(); + pgv_free +---------- + +(1 row) + +-- +-- +-- Functions pgv_free() + pgv_get() inside autonomous transaction; package +-- with regular variable; autonomous transaction with commit. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ERROR: unrecognized package "vars" + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ERROR: unrecognized package "vars" +ROLLBACK; +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- regular variable; autonomous transaction with commit. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ERROR: unrecognized package "vars" +ROLLBACK; +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- regular variable; autonomous transaction with rollback. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + ROLLBACK; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ERROR: unrecognized package "vars" +ROLLBACK; +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- transactional variable; autonomous transaction with rollback. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1, true); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + ROLLBACK; + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + +ROLLBACK; +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- transactional variable; autonomous transaction with commit. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1, true); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ERROR: unrecognized package "vars" +ROLLBACK; +-- +-- +-- Function pgv_free() inside recursive autonomous transactions. +-- +BEGIN; + BEGIN AUTONOMOUS; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; + BEGIN AUTONOMOUS; + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ERROR: unrecognized package "vars" + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ERROR: unrecognized package "vars" + COMMIT; +ROLLBACK; +-- +-- +-- Function pgv_free() inside recursive autonomous transactions; +-- recreating the package after deletion with using regular +-- variable. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; + BEGIN AUTONOMOUS; + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + + BEGIN AUTONOMOUS; + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ERROR: unrecognized package "vars" + COMMIT; + SELECT pgv_set('vars', 'int1', 2); + pgv_set +--------- + +(1 row) + + COMMIT; + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 2 +(1 row) + +ROLLBACK; +-- +-- +-- Function pgv_free() inside recursive autonomous transactions; +-- recreating the package after deletion with using transactional +-- variable. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; + BEGIN AUTONOMOUS; + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + + BEGIN AUTONOMOUS; + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ERROR: unrecognized package "vars" + COMMIT; + SELECT pgv_set('vars', 'int1', 2, true); + pgv_set +--------- + +(1 row) + + SELECT pgv_list(); + pgv_list +--------------- + (vars,int1,t) +(1 row) + + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ERROR: unrecognized package "vars" +ROLLBACK; +select pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/expected/pg_variables_atx_pkg_1.out b/expected/pg_variables_atx_pkg_1.out new file mode 100644 index 0000000..036c90f --- /dev/null +++ b/expected/pg_variables_atx_pkg_1.out @@ -0,0 +1,306 @@ +-- +-- PGPRO-7614: function pgv_free() inside autonomous transaction +-- +select pgv_free(); + pgv_free +---------- + +(1 row) + +-- +-- +-- Functions pgv_free() + pgv_get() inside autonomous transaction; package +-- with regular variable; autonomous transaction with commit. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_get('vars', 'int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + SELECT pgv_free(); +ERROR: current transaction is aborted, commands ignored until end of transaction block +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + +ROLLBACK; +WARNING: there is no transaction in progress +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- regular variable; autonomous transaction with commit. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_free(); +ERROR: current transaction is aborted, commands ignored until end of transaction block + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + +ROLLBACK; +WARNING: there is no transaction in progress +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- regular variable; autonomous transaction with rollback. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_free(); +ERROR: current transaction is aborted, commands ignored until end of transaction block + ROLLBACK; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + +ROLLBACK; +WARNING: there is no transaction in progress +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- transactional variable; autonomous transaction with rollback. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1, true); +ERROR: variable "int1" already created as NOT TRANSACTIONAL + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_free(); +ERROR: current transaction is aborted, commands ignored until end of transaction block + ROLLBACK; + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + +ROLLBACK; +WARNING: there is no transaction in progress +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- transactional variable; autonomous transaction with commit. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1, true); +ERROR: variable "int1" already created as NOT TRANSACTIONAL + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_free(); +ERROR: current transaction is aborted, commands ignored until end of transaction block + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + +ROLLBACK; +WARNING: there is no transaction in progress +-- +-- +-- Function pgv_free() inside recursive autonomous transactions. +-- +BEGIN; + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_set('vars', 'int1', 1); +ERROR: current transaction is aborted, commands ignored until end of transaction block + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_free(); +ERROR: current transaction is aborted, commands ignored until end of transaction block + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + + COMMIT; +WARNING: there is no transaction in progress +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + + COMMIT; +WARNING: there is no transaction in progress +ROLLBACK; +WARNING: there is no transaction in progress +-- +-- +-- Function pgv_free() inside recursive autonomous transactions; +-- recreating the package after deletion with using regular +-- variable. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_get('vars', 'int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_free(); +ERROR: current transaction is aborted, commands ignored until end of transaction block + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + + COMMIT; +WARNING: there is no transaction in progress + SELECT pgv_set('vars', 'int1', 2); + pgv_set +--------- + +(1 row) + + COMMIT; +WARNING: there is no transaction in progress + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 2 +(1 row) + +ROLLBACK; +WARNING: there is no transaction in progress +-- +-- +-- Function pgv_free() inside recursive autonomous transactions; +-- recreating the package after deletion with using transactional +-- variable. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_get('vars', 'int1', null::int); +ERROR: current transaction is aborted, commands ignored until end of transaction block + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_free(); +ERROR: current transaction is aborted, commands ignored until end of transaction block + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + + COMMIT; +WARNING: there is no transaction in progress + SELECT pgv_set('vars', 'int1', 2, true); +ERROR: variable "int1" already created as NOT TRANSACTIONAL + SELECT pgv_list(); + pgv_list +--------------- + (vars,int1,f) +(1 row) + + COMMIT; +WARNING: there is no transaction in progress +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + pgv_get +--------- + 1 +(1 row) + +ROLLBACK; +WARNING: there is no transaction in progress +select pgv_free(); + pgv_free +---------- + +(1 row) + diff --git a/pg_variables.c b/pg_variables.c index 9c571d7..a269291 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -2152,6 +2152,18 @@ removeObject(TransObject *object, TransObjectType type) #ifdef PGPRO_EE PackageContext *context, *next; + + /* + * Do not delete package inside autonomous transaction: it could be + * used in parent transaction. But we can delete package without any + * states: this means that the package was created in the current + * transaction. + */ + if (getNestLevelATX() > 0 && !dlist_is_empty(&object->states)) + { + GetActualState(object)->is_valid = false; + return; + } #endif package = (Package *) object; @@ -2171,6 +2183,8 @@ removeObject(TransObject *object, TransObjectType type) while (context) { next = context->next; + if (context->hctxTransact) + MemoryContextDelete(context->hctxTransact); pfree(context); context = next; } @@ -2764,11 +2778,15 @@ pgvRestoreContext() PackageContext *next = context->next; TransObject *object = &package->transObject; TransState *state; + bool actual_valid_state; /* Restore transactional variables from context */ package->hctxTransact = context->hctxTransact; package->varHashTransact = context->varHashTransact; + /* Save last actual state of package */ + actual_valid_state = GetActualState(object)->is_valid; + /* Remove all package states, generated in ATX transaction */ while ((state = GetActualState(object)) != context->state) { @@ -2778,6 +2796,18 @@ pgvRestoreContext() removeState(object, TRANS_PACKAGE, state); } + /* + * Package could be removed in the autonomous transaction. So + * need to mark it as invalid. Or removed package could be + * re-created - so need to mark it as valid. + */ + if (actual_valid_state != GetActualState(object)->is_valid) + GetActualState(object)->is_valid = actual_valid_state; + + /* Mark empty package as deleted. */ + if (GetPackState(package)->trans_var_num + numOfRegVars(package) == 0) + GetActualState(object)->is_valid = false; + pfree(context); package->context = next; } diff --git a/sql/pg_variables_atx_pkg.sql b/sql/pg_variables_atx_pkg.sql new file mode 100644 index 0000000..97a4ad3 --- /dev/null +++ b/sql/pg_variables_atx_pkg.sql @@ -0,0 +1,135 @@ +-- +-- PGPRO-7614: function pgv_free() inside autonomous transaction +-- +select pgv_free(); +-- +-- +-- Functions pgv_free() + pgv_get() inside autonomous transaction; package +-- with regular variable; autonomous transaction with commit. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + BEGIN AUTONOMOUS; + SELECT pgv_get('vars', 'int1', null::int); + SELECT pgv_free(); +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ROLLBACK; +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- regular variable; autonomous transaction with commit. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + BEGIN AUTONOMOUS; + SELECT pgv_free(); + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ROLLBACK; +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- regular variable; autonomous transaction with rollback. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + BEGIN AUTONOMOUS; + SELECT pgv_free(); + ROLLBACK; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ROLLBACK; +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- transactional variable; autonomous transaction with rollback. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1, true); + BEGIN AUTONOMOUS; + SELECT pgv_free(); + ROLLBACK; + SELECT pgv_get('vars', 'int1', null::int); +ROLLBACK; +-- +-- +-- Function pgv_free() inside autonomous transaction; package with +-- transactional variable; autonomous transaction with commit. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1, true); + BEGIN AUTONOMOUS; + SELECT pgv_free(); + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ROLLBACK; +-- +-- +-- Function pgv_free() inside recursive autonomous transactions. +-- +BEGIN; + BEGIN AUTONOMOUS; + SELECT pgv_set('vars', 'int1', 1); + BEGIN AUTONOMOUS; + BEGIN AUTONOMOUS; + SELECT pgv_free(); + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + COMMIT; +ROLLBACK; +-- +-- +-- Function pgv_free() inside recursive autonomous transactions; +-- recreating the package after deletion with using regular +-- variable. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + BEGIN AUTONOMOUS; + BEGIN AUTONOMOUS; + SELECT pgv_get('vars', 'int1', null::int); + BEGIN AUTONOMOUS; + SELECT pgv_free(); + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + COMMIT; + SELECT pgv_set('vars', 'int1', 2); + COMMIT; + SELECT pgv_get('vars', 'int1', null::int); +ROLLBACK; +-- +-- +-- Function pgv_free() inside recursive autonomous transactions; +-- recreating the package after deletion with using transactional +-- variable. +-- +BEGIN; + SELECT pgv_set('vars', 'int1', 1); + BEGIN AUTONOMOUS; + BEGIN AUTONOMOUS; + SELECT pgv_get('vars', 'int1', null::int); + BEGIN AUTONOMOUS; + SELECT pgv_free(); + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); + COMMIT; + SELECT pgv_set('vars', 'int1', 2, true); + SELECT pgv_list(); + COMMIT; +-- ERROR: unrecognized package "vars" + SELECT pgv_get('vars', 'int1', null::int); +ROLLBACK; + +select pgv_free(); From a6a399af333c0e895dc09b1b3566fecf73322e66 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Mon, 9 Jan 2023 10:46:13 +0300 Subject: [PATCH 36/46] [PGPRO-7614] Do not free hash_seq_search scans of parent transaction Tags: pg_variables, atx --- expected/pg_variables_atx_pkg.out | 21 +++++++++++++++++++++ expected/pg_variables_atx_pkg_1.out | 25 +++++++++++++++++++++++++ pg_variables.c | 8 ++++++++ sql/pg_variables_atx_pkg.sql | 11 +++++++++++ 4 files changed, 65 insertions(+) diff --git a/expected/pg_variables_atx_pkg.out b/expected/pg_variables_atx_pkg.out index a95e180..9af46e9 100644 --- a/expected/pg_variables_atx_pkg.out +++ b/expected/pg_variables_atx_pkg.out @@ -266,6 +266,27 @@ ERROR: unrecognized package "vars" SELECT pgv_get('vars', 'int1', null::int); ERROR: unrecognized package "vars" ROLLBACK; +-- +-- +-- Do not free hash_seq_search scans of parent transaction. +-- +BEGIN; + SELECT pgv_insert('test', 'x', row (1::int, 2::int), false); + pgv_insert +------------ + +(1 row) + + DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); + FETCH 1 IN r1_cur; + pgv_select +------------ + (1,2) +(1 row) + + BEGIN AUTONOMOUS; + ROLLBACK; +ROLLBACK; select pgv_free(); pgv_free ---------- diff --git a/expected/pg_variables_atx_pkg_1.out b/expected/pg_variables_atx_pkg_1.out index 036c90f..98a7bb9 100644 --- a/expected/pg_variables_atx_pkg_1.out +++ b/expected/pg_variables_atx_pkg_1.out @@ -296,6 +296,31 @@ WARNING: there is no transaction in progress 1 (1 row) +ROLLBACK; +WARNING: there is no transaction in progress +-- +-- +-- Do not free hash_seq_search scans of parent transaction. +-- +BEGIN; + SELECT pgv_insert('test', 'x', row (1::int, 2::int), false); + pgv_insert +------------ + +(1 row) + + DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); + FETCH 1 IN r1_cur; + pgv_select +------------ + (1,2) +(1 row) + + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + ROLLBACK; ROLLBACK; WARNING: there is no transaction in progress select pgv_free(); diff --git a/pg_variables.c b/pg_variables.c index a269291..6f2fa81 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -2951,7 +2951,11 @@ freeStatsLists(void) { VariableStatEntry *entry = (VariableStatEntry *) lfirst(cell); +#ifdef PGPRO_EE + hash_seq_term_all_levels(entry->status); +#else hash_seq_term(entry->status); +#endif } variables_stats = NIL; @@ -2960,7 +2964,11 @@ freeStatsLists(void) { PackageStatEntry *entry = (PackageStatEntry *) lfirst(cell); +#ifdef PGPRO_EE + hash_seq_term_all_levels(entry->status); +#else hash_seq_term(entry->status); +#endif } packages_stats = NIL; diff --git a/sql/pg_variables_atx_pkg.sql b/sql/pg_variables_atx_pkg.sql index 97a4ad3..fc73c26 100644 --- a/sql/pg_variables_atx_pkg.sql +++ b/sql/pg_variables_atx_pkg.sql @@ -131,5 +131,16 @@ BEGIN; -- ERROR: unrecognized package "vars" SELECT pgv_get('vars', 'int1', null::int); ROLLBACK; +-- +-- +-- Do not free hash_seq_search scans of parent transaction. +-- +BEGIN; + SELECT pgv_insert('test', 'x', row (1::int, 2::int), false); + DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); + FETCH 1 IN r1_cur; + BEGIN AUTONOMOUS; + ROLLBACK; +ROLLBACK; select pgv_free(); From 02d5dac06e42bf66da4bd0949afc9d990f1d7ca3 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Tue, 10 Jan 2023 00:09:18 +0300 Subject: [PATCH 37/46] [PGPRO-7614] Delete hash_seq_search scans on all ATX levels and before heap Tags: pg_variables, atx --- expected/pg_variables_atx_pkg.out | 62 +++++++++++++++++++++++++++-- expected/pg_variables_atx_pkg_1.out | 58 +++++++++++++++++++++++++-- pg_variables.c | 38 ++++++++++++++---- sql/pg_variables_atx_pkg.sql | 30 ++++++++++++-- 4 files changed, 172 insertions(+), 16 deletions(-) diff --git a/expected/pg_variables_atx_pkg.out b/expected/pg_variables_atx_pkg.out index 9af46e9..1d5025f 100644 --- a/expected/pg_variables_atx_pkg.out +++ b/expected/pg_variables_atx_pkg.out @@ -1,7 +1,7 @@ -- -- PGPRO-7614: function pgv_free() inside autonomous transaction -- -select pgv_free(); +SELECT pgv_free(); pgv_free ---------- @@ -268,7 +268,53 @@ ERROR: unrecognized package "vars" ROLLBACK; -- -- --- Do not free hash_seq_search scans of parent transaction. +-- Test for case: do not free hash_seq_search scans of parent transaction +-- at end of the autonomous transaction. +-- +BEGIN; + SELECT pgv_insert('test', 'x', row (1::int, 2::int), false); + pgv_insert +------------ + +(1 row) + + SELECT pgv_insert('test', 'x', row (3::int, 4::int), false); + pgv_insert +------------ + +(1 row) + + DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +-- (1,2) + FETCH 1 IN r1_cur; + pgv_select +------------ + (1,2) +(1 row) + + BEGIN AUTONOMOUS; + ROLLBACK; +-- (3,4) + FETCH 1 IN r1_cur; + pgv_select +------------ + (3,4) +(1 row) + + SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +-- ERROR: unrecognized package "test" + FETCH 1 IN r1_cur; +ERROR: unrecognized package "test" +ROLLBACK; +-- +-- +-- Test for case: pgv_free() should free hash_seq_search scans of all +-- (current ATX + parent) transactions. -- BEGIN; SELECT pgv_insert('test', 'x', row (1::int, 2::int), false); @@ -278,6 +324,7 @@ BEGIN; (1 row) DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +-- (1,2) FETCH 1 IN r1_cur; pgv_select ------------ @@ -285,9 +332,18 @@ BEGIN; (1 row) BEGIN AUTONOMOUS; + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + ROLLBACK; +-- ERROR: unrecognized package "test" + FETCH 1 IN r1_cur; +ERROR: unrecognized package "test" ROLLBACK; -select pgv_free(); +SELECT pgv_free(); pgv_free ---------- diff --git a/expected/pg_variables_atx_pkg_1.out b/expected/pg_variables_atx_pkg_1.out index 98a7bb9..b7fde58 100644 --- a/expected/pg_variables_atx_pkg_1.out +++ b/expected/pg_variables_atx_pkg_1.out @@ -1,7 +1,7 @@ -- -- PGPRO-7614: function pgv_free() inside autonomous transaction -- -select pgv_free(); +SELECT pgv_free(); pgv_free ---------- @@ -300,7 +300,53 @@ ROLLBACK; WARNING: there is no transaction in progress -- -- --- Do not free hash_seq_search scans of parent transaction. +-- Test for case: do not free hash_seq_search scans of parent transaction +-- at end of the autonomous transaction. +-- +BEGIN; + SELECT pgv_insert('test', 'x', row (1::int, 2::int), false); + pgv_insert +------------ + +(1 row) + + SELECT pgv_insert('test', 'x', row (3::int, 4::int), false); + pgv_insert +------------ + +(1 row) + + DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +-- (1,2) + FETCH 1 IN r1_cur; + pgv_select +------------ + (1,2) +(1 row) + + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + ROLLBACK; +-- (3,4) + FETCH 1 IN r1_cur; +ERROR: cursor "r1_cur" does not exist + SELECT pgv_remove('test', 'x'); + pgv_remove +------------ + +(1 row) + +-- ERROR: unrecognized package "test" + FETCH 1 IN r1_cur; +ERROR: cursor "r1_cur" does not exist +ROLLBACK; +WARNING: there is no transaction in progress +-- +-- +-- Test for case: pgv_free() should free hash_seq_search scans of all +-- (current ATX + parent) transactions. -- BEGIN; SELECT pgv_insert('test', 'x', row (1::int, 2::int), false); @@ -310,6 +356,7 @@ BEGIN; (1 row) DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +-- (1,2) FETCH 1 IN r1_cur; pgv_select ------------ @@ -320,10 +367,15 @@ BEGIN; ERROR: syntax error at or near "AUTONOMOUS" LINE 1: BEGIN AUTONOMOUS; ^ + SELECT pgv_free(); +ERROR: current transaction is aborted, commands ignored until end of transaction block ROLLBACK; +-- ERROR: unrecognized package "test" + FETCH 1 IN r1_cur; +ERROR: cursor "r1_cur" does not exist ROLLBACK; WARNING: there is no transaction in progress -select pgv_free(); +SELECT pgv_free(); pgv_free ---------- diff --git a/pg_variables.c b/pg_variables.c index 6f2fa81..5a319fc 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -310,7 +310,11 @@ list_remove_if(RemoveIfContext ctx) *ctx.list = list_delete_cell(*ctx.list, cell, prev); if (ctx.term) +#ifdef PGPRO_EE + hash_seq_term_all_levels(ctx.getter(entry)); +#else hash_seq_term(ctx.getter(entry)); +#endif pfree(ctx.getter(entry)); pfree(entry); @@ -342,7 +346,11 @@ list_remove_if(RemoveIfContext ctx) *ctx.list = foreach_delete_current(*ctx.list, cell); if (ctx.term) +#ifdef PGPRO_EE + hash_seq_term_all_levels(ctx.getter(entry)); +#else hash_seq_term(ctx.getter(entry)); +#endif pfree(ctx.getter(entry)); pfree(entry); @@ -1338,12 +1346,17 @@ remove_package(PG_FUNCTION_ARGS) package_name = PG_GETARG_TEXT_PP(0); package = getPackage(package_name, true); + /* + * Need to remove variables before packages because here calls hash_seq_term() + * which uses "entry->status->hashp->frozen" but memory context of "hashp" + * for regular variables can be deleted in removePackageInternal(). + */ + remove_variables_package(&variables_stats, package); + removePackageInternal(package); resetVariablesCache(); - remove_variables_package(&variables_stats, package); - PG_FREE_IF_COPY(package_name, 0); PG_RETURN_VOID(); } @@ -1430,6 +1443,13 @@ remove_packages(PG_FUNCTION_ARGS) if (packagesHash == NULL) PG_RETURN_VOID(); + /* + * Need to remove variables before packages because here calls hash_seq_term() + * which uses "entry->status->hashp->frozen" but memory context of "hashp" + * for regular variables can be deleted in removePackageInternal(). + */ + remove_variables_all(&variables_stats); + /* Get packages list */ hash_seq_init(&pstat, packagesHash); while ((package = (Package *) hash_seq_search(&pstat)) != NULL) @@ -1438,7 +1458,6 @@ remove_packages(PG_FUNCTION_ARGS) } resetVariablesCache(); - remove_variables_all(&variables_stats); PG_RETURN_VOID(); } @@ -2201,14 +2220,19 @@ removeObject(TransObject *object, TransObjectType type) var->package->varHashRegular; } + /* + * Need to remove variables before state because here calls hash_seq_term() + * which uses "entry->status->hashp->frozen" but memory context of "hashp" + * for regular variables can be deleted in removeState()->freeValue(). + */ + /* Remove object from hash table */ + hash_search(hash, object->name, HASH_REMOVE, &found); + remove_variables_variable(&variables_stats, (Variable*)object); + /* Remove all object's states */ while (!dlist_is_empty(&object->states)) removeState(object, type, GetActualState(object)); - /* Remove object from hash table */ - hash_search(hash, object->name, HASH_REMOVE, &found); - remove_variables_variable(&variables_stats, (Variable *) object); - /* Remove package if it became empty */ if (type == TRANS_VARIABLE && isPackageEmpty(package)) { diff --git a/sql/pg_variables_atx_pkg.sql b/sql/pg_variables_atx_pkg.sql index fc73c26..1d6a6cb 100644 --- a/sql/pg_variables_atx_pkg.sql +++ b/sql/pg_variables_atx_pkg.sql @@ -1,7 +1,7 @@ -- -- PGPRO-7614: function pgv_free() inside autonomous transaction -- -select pgv_free(); +SELECT pgv_free(); -- -- -- Functions pgv_free() + pgv_get() inside autonomous transaction; package @@ -133,14 +133,38 @@ BEGIN; ROLLBACK; -- -- --- Do not free hash_seq_search scans of parent transaction. +-- Test for case: do not free hash_seq_search scans of parent transaction +-- at end of the autonomous transaction. -- BEGIN; SELECT pgv_insert('test', 'x', row (1::int, 2::int), false); + SELECT pgv_insert('test', 'x', row (3::int, 4::int), false); DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +-- (1,2) FETCH 1 IN r1_cur; BEGIN AUTONOMOUS; ROLLBACK; +-- (3,4) + FETCH 1 IN r1_cur; + SELECT pgv_remove('test', 'x'); +-- ERROR: unrecognized package "test" + FETCH 1 IN r1_cur; +ROLLBACK; +-- +-- +-- Test for case: pgv_free() should free hash_seq_search scans of all +-- (current ATX + parent) transactions. +-- +BEGIN; + SELECT pgv_insert('test', 'x', row (1::int, 2::int), false); + DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); +-- (1,2) + FETCH 1 IN r1_cur; + BEGIN AUTONOMOUS; + SELECT pgv_free(); + ROLLBACK; +-- ERROR: unrecognized package "test" + FETCH 1 IN r1_cur; ROLLBACK; -select pgv_free(); +SELECT pgv_free(); From afdef5405e9de88eb4548ea0f6a9150add44c749 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Wed, 11 Jan 2023 23:19:15 +0300 Subject: [PATCH 38/46] [PGPRO-7614] Fix crash by using cursor after rollback of cursor creation Tags: pg_variables --- expected/pg_variables_trans.out | 48 ++++++++++++++++++++++++ expected/pg_variables_trans_0.out | 48 ++++++++++++++++++++++++ pg_variables.c | 61 +++++++++++++++++++++++++++---- sql/pg_variables_trans.sql | 22 +++++++++++ 4 files changed, 171 insertions(+), 8 deletions(-) diff --git a/expected/pg_variables_trans.out b/expected/pg_variables_trans.out index 09f56c8..4370646 100644 --- a/expected/pg_variables_trans.out +++ b/expected/pg_variables_trans.out @@ -3834,3 +3834,51 @@ SELECT pgv_free(); -- SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE); ERROR: could not identify a hash function for type record +-- +-- Test case for PGPRO-7614: crash by using cursor after rollback of cursor +-- creation. +-- +BEGIN; + SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), true); + pgv_insert +------------ + +(1 row) + + DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); + SAVEPOINT sp1; + FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + + ROLLBACK TO SAVEPOINT sp1; + FETCH 1 in r1_cur; + pgv_select +------------ +(0 rows) + +ROLLBACK; +BEGIN; + SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + + DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); + SAVEPOINT sp1; + FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + + ROLLBACK TO SAVEPOINT sp1; + FETCH 1 in r1_cur; + pgv_stats +----------- +(0 rows) + +ROLLBACK; diff --git a/expected/pg_variables_trans_0.out b/expected/pg_variables_trans_0.out index 7c29138..8a3c54c 100644 --- a/expected/pg_variables_trans_0.out +++ b/expected/pg_variables_trans_0.out @@ -3838,3 +3838,51 @@ SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE); (1 row) +-- +-- Test case for PGPRO-7614: crash by using cursor after rollback of cursor +-- creation. +-- +BEGIN; + SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), true); + pgv_insert +------------ + +(1 row) + + DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); + SAVEPOINT sp1; + FETCH 1 in r1_cur; + pgv_select +------------ + (1,2) +(1 row) + + ROLLBACK TO SAVEPOINT sp1; + FETCH 1 in r1_cur; + pgv_select +------------ +(0 rows) + +ROLLBACK; +BEGIN; + SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + pgv_insert +------------ + +(1 row) + + DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); + SAVEPOINT sp1; + FETCH 1 in r1_cur; + pgv_stats +-------------- + (test,32768) +(1 row) + + ROLLBACK TO SAVEPOINT sp1; + FETCH 1 in r1_cur; + pgv_stats +----------- +(0 rows) + +ROLLBACK; diff --git a/pg_variables.c b/pg_variables.c index 5a319fc..2afb5ec 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -166,12 +166,14 @@ typedef struct tagVariableStatEntry Variable *variable; Package *package; Levels levels; + void **user_fctx; /* pointer to funcctx->user_fctx */ } VariableStatEntry; typedef struct tagPackageStatEntry { HASH_SEQ_STATUS *status; Levels levels; + void **user_fctx; /* pointer to funcctx->user_fctx */ } PackageStatEntry; #ifdef PGPRO_EE @@ -268,6 +270,25 @@ PackageStatEntry_status_ptr(void *entry) return ((PackageStatEntry *) entry)->status; } +/* + * VariableStatEntry and PackageStatEntry functions for clear function context. + */ +static void +VariableStatEntry_clear_fctx(void *entry) +{ + VariableStatEntry *e = (VariableStatEntry *) entry; + if (e->user_fctx) + *e->user_fctx = NULL; +} + +static void +PackageStatEntry_clear_fctx(void *entry) +{ + PackageStatEntry *e = (PackageStatEntry *) entry; + if (e->user_fctx) + *e->user_fctx = NULL; +} + /* * Generic remove_if algorithm. * @@ -289,6 +310,7 @@ typedef struct tagRemoveIfContext HASH_SEQ_STATUS *(*getter) (void *); /* status getter */ bool match_first; /* return on first match */ bool term; /* hash_seq_term on match */ + void (*clear_fctx) (void *); /* clear function context */ } RemoveIfContext; static void @@ -316,6 +338,8 @@ list_remove_if(RemoveIfContext ctx) hash_seq_term(ctx.getter(entry)); #endif + ctx.clear_fctx(entry); + pfree(ctx.getter(entry)); pfree(entry); @@ -352,6 +376,8 @@ list_remove_if(RemoveIfContext ctx) hash_seq_term(ctx.getter(entry)); #endif + ctx.clear_fctx(entry); + pfree(ctx.getter(entry)); pfree(entry); @@ -375,7 +401,8 @@ remove_variables_status(List **list, HASH_SEQ_STATUS *status) .eq = VariableStatEntry_status_eq, .getter = VariableStatEntry_status_ptr, .match_first = true, - .term = false + .term = false, + .clear_fctx = VariableStatEntry_clear_fctx }; list_remove_if(ctx); @@ -398,7 +425,8 @@ remove_variables_variable(List **list, Variable *variable) .eq = VariableStatEntry_variable_eq, .getter = VariableStatEntry_status_ptr, .match_first = false, - .term = true + .term = true, + .clear_fctx = VariableStatEntry_clear_fctx }; list_remove_if(ctx); @@ -417,7 +445,8 @@ remove_variables_package(List **list, Package *package) .eq = VariableStatEntry_package_eq, .getter = VariableStatEntry_status_ptr, .match_first = false, - .term = true + .term = true, + .clear_fctx = VariableStatEntry_clear_fctx }; list_remove_if(ctx); @@ -436,7 +465,8 @@ remove_variables_level(List **list, Levels *levels) .eq = VariableStatEntry_level_eq, .getter = VariableStatEntry_status_ptr, .match_first = false, - .term = false + .term = false, + .clear_fctx = VariableStatEntry_clear_fctx }; list_remove_if(ctx); @@ -455,7 +485,8 @@ remove_variables_all(List **list) .eq = VariableStatEntry_eq_all, .getter = VariableStatEntry_status_ptr, .match_first = false, - .term = true + .term = true, + .clear_fctx = VariableStatEntry_clear_fctx }; list_remove_if(ctx); @@ -474,7 +505,8 @@ remove_packages_status(List **list, HASH_SEQ_STATUS *status) .eq = PackageStatEntry_status_eq, .getter = PackageStatEntry_status_ptr, .match_first = true, - .term = false + .term = false, + .clear_fctx = PackageStatEntry_clear_fctx }; list_remove_if(ctx); @@ -493,7 +525,8 @@ remove_packages_level(List **list, Levels *levels) .eq = PackageStatEntry_level_eq, .getter = PackageStatEntry_status_ptr, .match_first = false, - .term = true + .term = true, + .clear_fctx = PackageStatEntry_clear_fctx }; list_remove_if(ctx); @@ -513,7 +546,8 @@ remove_variables_transactional(List **list) .eq = VariableStatEntry_is_transactional, .getter = VariableStatEntry_status_ptr, .match_first = false, - .term = true + .term = true, + .clear_fctx = VariableStatEntry_clear_fctx }; list_remove_if(ctx); @@ -1027,6 +1061,7 @@ variable_select(PG_FUNCTION_ARGS) #ifdef PGPRO_EE entry->levels.atxlevel = getNestLevelATX(); #endif + entry->user_fctx = &funcctx->user_fctx; variables_stats = lcons((void *) entry, variables_stats); MemoryContextSwitchTo(oldcontext); @@ -1036,6 +1071,15 @@ variable_select(PG_FUNCTION_ARGS) funcctx = SRF_PERCALL_SETUP(); + if (funcctx->user_fctx == NULL) + { + /* + * VariableStatEntry was removed. For example, after call + * 'ROLLBACK TO SAVEPOINT ...' + */ + SRF_RETURN_DONE(funcctx); + } + /* Get next hash record */ rstat = (HASH_SEQ_STATUS *) funcctx->user_fctx; item = (HashRecordEntry *) hash_seq_search(rstat); @@ -1672,6 +1716,7 @@ get_packages_stats(PG_FUNCTION_ARGS) #ifdef PGPRO_EE entry->levels.atxlevel = getNestLevelATX(); #endif + entry->user_fctx = &funcctx->user_fctx; packages_stats = lcons((void *) entry, packages_stats); MemoryContextSwitchTo(ctx); } diff --git a/sql/pg_variables_trans.sql b/sql/pg_variables_trans.sql index ae69df7..23b7afd 100644 --- a/sql/pg_variables_trans.sql +++ b/sql/pg_variables_trans.sql @@ -1169,3 +1169,25 @@ SELECT pgv_free(); -- Test case for issue #38 [PGPRO-4676] -- SELECT pgv_insert('test', 'x5', ROW ((2::int, 1::int)), TRUE); + +-- +-- Test case for PGPRO-7614: crash by using cursor after rollback of cursor +-- creation. +-- +BEGIN; + SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), true); + DECLARE r1_cur CURSOR FOR SELECT pgv_select('test', 'x'); + SAVEPOINT sp1; + FETCH 1 in r1_cur; + ROLLBACK TO SAVEPOINT sp1; + FETCH 1 in r1_cur; +ROLLBACK; + +BEGIN; + SELECT pgv_insert('test', 'x', ROW (1::int, 2::int), TRUE); + DECLARE r1_cur CURSOR FOR SELECT pgv_stats(); + SAVEPOINT sp1; + FETCH 1 in r1_cur; + ROLLBACK TO SAVEPOINT sp1; + FETCH 1 in r1_cur; +ROLLBACK; From 98737561940703ce93a6511854d1f1bb433ef7d5 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Fri, 13 Jan 2023 15:16:40 +0300 Subject: [PATCH 39/46] [PGPRO-7614] Fix error that caused by replacement of package state at end of autonomous transaction Tags: pg_variables, atx --- expected/pg_variables_atx_pkg.out | 31 +++++++++++++++++++++++++ expected/pg_variables_atx_pkg_1.out | 35 +++++++++++++++++++++++++++++ pg_variables.c | 9 +++++++- sql/pg_variables_atx_pkg.sql | 16 +++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/expected/pg_variables_atx_pkg.out b/expected/pg_variables_atx_pkg.out index 1d5025f..c69b325 100644 --- a/expected/pg_variables_atx_pkg.out +++ b/expected/pg_variables_atx_pkg.out @@ -343,6 +343,37 @@ BEGIN; FETCH 1 IN r1_cur; ERROR: unrecognized package "test" ROLLBACK; +-- +-- +-- Test for case: pgv_set() created regular a variable; rollback +-- removes package state and creates a new state to make package valid. +-- Commit of next autonomous transaction should not replace this new +-- state (this is not allowed for autonomous transaction). +-- +BEGIN; + BEGIN AUTONOMOUS; + SELECT pgv_set('vars', 'int1', 1); + pgv_set +--------- + +(1 row) + + ROLLBACK; + BEGIN AUTONOMOUS; + SELECT pgv_set('vars', 'int1', 2); + pgv_set +--------- + +(1 row) + + COMMIT; +ROLLBACK; +SELECT pgv_remove('vars', 'int1'); + pgv_remove +------------ + +(1 row) + SELECT pgv_free(); pgv_free ---------- diff --git a/expected/pg_variables_atx_pkg_1.out b/expected/pg_variables_atx_pkg_1.out index b7fde58..e2bb3b2 100644 --- a/expected/pg_variables_atx_pkg_1.out +++ b/expected/pg_variables_atx_pkg_1.out @@ -375,6 +375,41 @@ ERROR: current transaction is aborted, commands ignored until end of transactio ERROR: cursor "r1_cur" does not exist ROLLBACK; WARNING: there is no transaction in progress +-- +-- +-- Test for case: pgv_set() created regular a variable; rollback +-- removes package state and creates a new state to make package valid. +-- Commit of next autonomous transaction should not replace this new +-- state (this is not allowed for autonomous transaction). +-- +BEGIN; + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_set('vars', 'int1', 1); +ERROR: current transaction is aborted, commands ignored until end of transaction block + ROLLBACK; + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_set('vars', 'int1', 2); + pgv_set +--------- + +(1 row) + + COMMIT; +WARNING: there is no transaction in progress +ROLLBACK; +WARNING: there is no transaction in progress +SELECT pgv_remove('vars', 'int1'); + pgv_remove +------------ + +(1 row) + SELECT pgv_free(); pgv_free ---------- diff --git a/pg_variables.c b/pg_variables.c index 2afb5ec..ea0ba02 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -2354,7 +2354,14 @@ rollbackSavepoint(TransObject *object, TransObjectType type) /* ...create a new state to make package valid. */ initObjectHistory(object, type); #ifdef PGPRO_EE - GetActualState(object)->levels.atxlevel = getNestLevelATX(); + /* + * Package inside autonomous transaction should not be detected + * as 'object has been changed in upper level' because in this + * case we will remove state in releaseSavepoint() but this + * state may be used pgvRestoreContext(). So atxlevel should + * be 0. + */ + GetActualState(object)->levels.atxlevel = 0; #endif GetActualState(object)->levels.level = GetCurrentTransactionNestLevel() - 1; if (!dlist_is_empty(changesStack)) diff --git a/sql/pg_variables_atx_pkg.sql b/sql/pg_variables_atx_pkg.sql index 1d6a6cb..c117796 100644 --- a/sql/pg_variables_atx_pkg.sql +++ b/sql/pg_variables_atx_pkg.sql @@ -166,5 +166,21 @@ BEGIN; -- ERROR: unrecognized package "test" FETCH 1 IN r1_cur; ROLLBACK; +-- +-- +-- Test for case: pgv_set() created regular a variable; rollback +-- removes package state and creates a new state to make package valid. +-- Commit of next autonomous transaction should not replace this new +-- state (this is not allowed for autonomous transaction). +-- +BEGIN; + BEGIN AUTONOMOUS; + SELECT pgv_set('vars', 'int1', 1); + ROLLBACK; + BEGIN AUTONOMOUS; + SELECT pgv_set('vars', 'int1', 2); + COMMIT; +ROLLBACK; +SELECT pgv_remove('vars', 'int1'); SELECT pgv_free(); From 2b5fd99f4cd26ebddc4159b8a3f68848149be42a Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Mon, 16 Jan 2023 13:47:20 +0300 Subject: [PATCH 40/46] [PGPRO-7614] Fix error caused by unchanged package state's ATX-level at autonomous transaction commit Tags: pg_variables, atx --- expected/pg_variables_atx_pkg.out | 34 ++++++++++++++++++++- expected/pg_variables_atx_pkg_1.out | 38 +++++++++++++++++++++++- pg_variables.c | 46 ++++++++++++++++++++--------- sql/pg_variables_atx_pkg.sql | 19 +++++++++++- 4 files changed, 120 insertions(+), 17 deletions(-) diff --git a/expected/pg_variables_atx_pkg.out b/expected/pg_variables_atx_pkg.out index c69b325..f6c1d13 100644 --- a/expected/pg_variables_atx_pkg.out +++ b/expected/pg_variables_atx_pkg.out @@ -345,7 +345,7 @@ ERROR: unrecognized package "test" ROLLBACK; -- -- --- Test for case: pgv_set() created regular a variable; rollback +-- Test for case: pgv_set() created a regular variable; rollback -- removes package state and creates a new state to make package valid. -- Commit of next autonomous transaction should not replace this new -- state (this is not allowed for autonomous transaction). @@ -374,6 +374,38 @@ SELECT pgv_remove('vars', 'int1'); (1 row) +-- +-- +-- Test for case: pgv_set() created a regular variable and package with +-- (atxlevel=1, level=1). COMMIT changes this level to (atxlevel=1, level=0). +-- In the next autonomous transaction (atxlevel=1, level=1) we erroneously +-- detect that the package changed in upper transaction and remove the +-- package state (this is not allowed for autonomous transaction). +-- +BEGIN; + BEGIN AUTONOMOUS; + SELECT pgv_set('vars', 'int1', 2); + pgv_set +--------- + +(1 row) + + COMMIT; + BEGIN AUTONOMOUS; + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + SELECT pgv_set('vars', 'int1', 2, true); + pgv_set +--------- + +(1 row) + + COMMIT; +ROLLBACK; SELECT pgv_free(); pgv_free ---------- diff --git a/expected/pg_variables_atx_pkg_1.out b/expected/pg_variables_atx_pkg_1.out index e2bb3b2..a579e44 100644 --- a/expected/pg_variables_atx_pkg_1.out +++ b/expected/pg_variables_atx_pkg_1.out @@ -377,7 +377,7 @@ ROLLBACK; WARNING: there is no transaction in progress -- -- --- Test for case: pgv_set() created regular a variable; rollback +-- Test for case: pgv_set() created a regular variable; rollback -- removes package state and creates a new state to make package valid. -- Commit of next autonomous transaction should not replace this new -- state (this is not allowed for autonomous transaction). @@ -410,6 +410,42 @@ SELECT pgv_remove('vars', 'int1'); (1 row) +-- +-- +-- Test for case: pgv_set() created a regular variable and package with +-- (atxlevel=1, level=1). COMMIT changes this level to (atxlevel=1, level=0). +-- In the next autonomous transaction (atxlevel=1, level=1) we erroneously +-- detect that the package changed in upper transaction and remove the +-- package state (this is not allowed for autonomous transaction). +-- +BEGIN; + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_set('vars', 'int1', 2); +ERROR: current transaction is aborted, commands ignored until end of transaction block + COMMIT; + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + SELECT pgv_set('vars', 'int1', 2, true); + pgv_set +--------- + +(1 row) + + COMMIT; +WARNING: there is no transaction in progress +ROLLBACK; +WARNING: there is no transaction in progress SELECT pgv_free(); pgv_free ---------- diff --git a/pg_variables.c b/pg_variables.c index ea0ba02..9b0775b 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -64,7 +64,7 @@ static void resetVariablesCache(void); /* Functions to work with transactional objects */ static void createSavepoint(TransObject *object, TransObjectType type); -static void releaseSavepoint(TransObject *object, TransObjectType type); +static void releaseSavepoint(TransObject *object, TransObjectType type, bool sub); static void rollbackSavepoint(TransObject *object, TransObjectType type); static void copyValue(VarState *src, VarState *dest, Variable *destVar); @@ -2408,11 +2408,14 @@ rollbackSavepoint(TransObject *object, TransObjectType type) * Remove previous state of object */ static void -releaseSavepoint(TransObject *object, TransObjectType type) +releaseSavepoint(TransObject *object, TransObjectType type, bool sub) { dlist_head *states = &object->states; Assert(GetActualState(object)->levels.level == GetCurrentTransactionNestLevel()); +#ifdef PGPRO_EE + Assert(GetActualState(object)->levels.atxlevel == getNestLevelATX()); +#endif /* * If the object is not valid and does not exist at a higher level (or if @@ -2438,6 +2441,15 @@ releaseSavepoint(TransObject *object, TransObjectType type) nodeToDelete = dlist_next_node(states, dlist_head_node(states)); stateToDelete = dlist_container(TransState, node, nodeToDelete); +#ifdef PGPRO_EE + /* + * We can not delete package state inside autonomous transaction + * because the state can be used in pgvRestoreContext(). + * Exception: the state was created within this autonomous transaction. + */ + Assert(type != TRANS_PACKAGE || getNestLevelATX() == 0 || + stateToDelete->levels.atxlevel == getNestLevelATX()); +#endif removeState(object, type, stateToDelete); } @@ -2450,6 +2462,12 @@ releaseSavepoint(TransObject *object, TransObjectType type) /* Change subxact level due to release */ GetActualState(object)->levels.level--; + +#ifdef PGPRO_EE + /* Change ATX level due to finish autonomous transaction */ + if (!sub && getNestLevelATX() > 0) + GetActualState(object)->levels.atxlevel = 0; +#endif } static void @@ -2647,7 +2665,7 @@ typedef enum Action * Apply savepoint actions on list of variables or packages. */ static void -applyAction(Action action, TransObjectType type, dlist_head *list) +applyAction(Action action, TransObjectType type, dlist_head *list, bool sub) { dlist_iter iter; @@ -2677,7 +2695,7 @@ applyAction(Action action, TransObjectType type, dlist_head *list) GetActualState(variable)->is_valid = false; } - releaseSavepoint(object, type); + releaseSavepoint(object, type, sub); break; } } @@ -2688,7 +2706,7 @@ applyAction(Action action, TransObjectType type, dlist_head *list) * apply corresponding action on them */ static void -processChanges(Action action) +processChanges(Action action, bool sub) { ChangesStackNode *bottom_list; @@ -2697,8 +2715,8 @@ processChanges(Action action) bottom_list = dlist_container(ChangesStackNode, node, dlist_pop_head_node(changesStack)); - applyAction(action, TRANS_VARIABLE, bottom_list->changedVarsList); - applyAction(action, TRANS_PACKAGE, bottom_list->changedPacksList); + applyAction(action, TRANS_VARIABLE, bottom_list->changedVarsList, sub); + applyAction(action, TRANS_PACKAGE, bottom_list->changedPacksList, sub); /* Remove changes list of current level */ MemoryContextDelete(bottom_list->ctx); @@ -2866,10 +2884,10 @@ pgvRestoreContext() /* Remove all package states, generated in ATX transaction */ while ((state = GetActualState(object)) != context->state) { + removeState(object, TRANS_PACKAGE, state); if (dlist_is_empty(&object->states)) elog(ERROR, "pg_variables extension can not find " "transaction state for package"); - removeState(object, TRANS_PACKAGE, state); } /* @@ -2935,10 +2953,10 @@ pgvSubTransCallback(SubXactEvent event, SubTransactionId mySubid, compatibility_check(); break; case SUBXACT_EVENT_COMMIT_SUB: - processChanges(RELEASE_SAVEPOINT); + processChanges(RELEASE_SAVEPOINT, true); break; case SUBXACT_EVENT_ABORT_SUB: - processChanges(ROLLBACK_TO_SAVEPOINT); + processChanges(ROLLBACK_TO_SAVEPOINT, true); break; case SUBXACT_EVENT_PRE_COMMIT_SUB: break; @@ -2965,16 +2983,16 @@ pgvTransCallback(XactEvent event, void *arg) { case XACT_EVENT_PRE_COMMIT: compatibility_check(); - processChanges(RELEASE_SAVEPOINT); + processChanges(RELEASE_SAVEPOINT, false); break; case XACT_EVENT_ABORT: - processChanges(ROLLBACK_TO_SAVEPOINT); + processChanges(ROLLBACK_TO_SAVEPOINT, false); break; case XACT_EVENT_PARALLEL_PRE_COMMIT: - processChanges(RELEASE_SAVEPOINT); + processChanges(RELEASE_SAVEPOINT, false); break; case XACT_EVENT_PARALLEL_ABORT: - processChanges(ROLLBACK_TO_SAVEPOINT); + processChanges(ROLLBACK_TO_SAVEPOINT, false); break; default: break; diff --git a/sql/pg_variables_atx_pkg.sql b/sql/pg_variables_atx_pkg.sql index c117796..ee21dfc 100644 --- a/sql/pg_variables_atx_pkg.sql +++ b/sql/pg_variables_atx_pkg.sql @@ -168,7 +168,7 @@ BEGIN; ROLLBACK; -- -- --- Test for case: pgv_set() created regular a variable; rollback +-- Test for case: pgv_set() created a regular variable; rollback -- removes package state and creates a new state to make package valid. -- Commit of next autonomous transaction should not replace this new -- state (this is not allowed for autonomous transaction). @@ -182,5 +182,22 @@ BEGIN; COMMIT; ROLLBACK; SELECT pgv_remove('vars', 'int1'); +-- +-- +-- Test for case: pgv_set() created a regular variable and package with +-- (atxlevel=1, level=1). COMMIT changes this level to (atxlevel=1, level=0). +-- In the next autonomous transaction (atxlevel=1, level=1) we erroneously +-- detect that the package changed in upper transaction and remove the +-- package state (this is not allowed for autonomous transaction). +-- +BEGIN; + BEGIN AUTONOMOUS; + SELECT pgv_set('vars', 'int1', 2); + COMMIT; + BEGIN AUTONOMOUS; + SELECT pgv_free(); + SELECT pgv_set('vars', 'int1', 2, true); + COMMIT; +ROLLBACK; SELECT pgv_free(); From c7898fce63c0b795541691b9117c491d04e87835 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Tue, 17 Jan 2023 15:22:55 +0300 Subject: [PATCH 41/46] [PGPRO-7614] Fix error caused by changing ATX level of package state at sub-transaction commit Tags: pg_variables, atx --- expected/pg_variables_atx_pkg.out | 24 ++++++++++++++++++++++++ expected/pg_variables_atx_pkg_1.out | 22 ++++++++++++++++++++++ pg_variables.c | 10 +++++----- sql/pg_variables_atx_pkg.sql | 14 ++++++++++++++ 4 files changed, 65 insertions(+), 5 deletions(-) diff --git a/expected/pg_variables_atx_pkg.out b/expected/pg_variables_atx_pkg.out index f6c1d13..527d5cc 100644 --- a/expected/pg_variables_atx_pkg.out +++ b/expected/pg_variables_atx_pkg.out @@ -406,6 +406,30 @@ BEGIN; COMMIT; ROLLBACK; +-- +-- +-- Test for case: pgv_set() created a regular variable and package with +-- (atxlevel=1, level=1). ROLLBACK changes this level to (atxlevel=0, level=0). +-- But ROLLBACK shouldn't change atxlevel in case rollback of sub-transaction. +-- +BEGIN; + BEGIN AUTONOMOUS; + SAVEPOINT sp1; + SELECT pgv_set('vars1', 'int1', 0); + pgv_set +--------- + +(1 row) + + ROLLBACK TO sp1; + COMMIT; +ROLLBACK; +SELECT pgv_remove('vars1', 'int1'); + pgv_remove +------------ + +(1 row) + SELECT pgv_free(); pgv_free ---------- diff --git a/expected/pg_variables_atx_pkg_1.out b/expected/pg_variables_atx_pkg_1.out index a579e44..d45c6ce 100644 --- a/expected/pg_variables_atx_pkg_1.out +++ b/expected/pg_variables_atx_pkg_1.out @@ -446,6 +446,28 @@ LINE 1: BEGIN AUTONOMOUS; WARNING: there is no transaction in progress ROLLBACK; WARNING: there is no transaction in progress +-- +-- +-- Test for case: pgv_set() created a regular variable and package with +-- (atxlevel=1, level=1). ROLLBACK changes this level to (atxlevel=0, level=0). +-- But ROLLBACK shouldn't change atxlevel in case rollback of sub-transaction. +-- +BEGIN; + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SAVEPOINT sp1; +ERROR: current transaction is aborted, commands ignored until end of transaction block + SELECT pgv_set('vars1', 'int1', 0); +ERROR: current transaction is aborted, commands ignored until end of transaction block + ROLLBACK TO sp1; +ERROR: savepoint "sp1" does not exist + COMMIT; +ROLLBACK; +WARNING: there is no transaction in progress +SELECT pgv_remove('vars1', 'int1'); +ERROR: unrecognized package "vars1" SELECT pgv_free(); pgv_free ---------- diff --git a/pg_variables.c b/pg_variables.c index 9b0775b..fd6e2f9 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -65,7 +65,7 @@ static void resetVariablesCache(void); /* Functions to work with transactional objects */ static void createSavepoint(TransObject *object, TransObjectType type); static void releaseSavepoint(TransObject *object, TransObjectType type, bool sub); -static void rollbackSavepoint(TransObject *object, TransObjectType type); +static void rollbackSavepoint(TransObject *object, TransObjectType type, bool sub); static void copyValue(VarState *src, VarState *dest, Variable *destVar); static void freeValue(VarState *varstate, bool is_record); @@ -2329,7 +2329,7 @@ numOfRegVars(Package *package) * Rollback object to its previous state */ static void -rollbackSavepoint(TransObject *object, TransObjectType type) +rollbackSavepoint(TransObject *object, TransObjectType type, bool sub) { TransState *state; @@ -2359,9 +2359,9 @@ rollbackSavepoint(TransObject *object, TransObjectType type) * as 'object has been changed in upper level' because in this * case we will remove state in releaseSavepoint() but this * state may be used pgvRestoreContext(). So atxlevel should - * be 0. + * be 0 in case rollback of autonomous transaction. */ - GetActualState(object)->levels.atxlevel = 0; + GetActualState(object)->levels.atxlevel = sub ? getNestLevelATX() : 0; #endif GetActualState(object)->levels.level = GetCurrentTransactionNestLevel() - 1; if (!dlist_is_empty(changesStack)) @@ -2677,7 +2677,7 @@ applyAction(Action action, TransObjectType type, dlist_head *list, bool sub) switch (action) { case ROLLBACK_TO_SAVEPOINT: - rollbackSavepoint(object, type); + rollbackSavepoint(object, type, sub); break; case RELEASE_SAVEPOINT: diff --git a/sql/pg_variables_atx_pkg.sql b/sql/pg_variables_atx_pkg.sql index ee21dfc..a4a4943 100644 --- a/sql/pg_variables_atx_pkg.sql +++ b/sql/pg_variables_atx_pkg.sql @@ -199,5 +199,19 @@ BEGIN; SELECT pgv_set('vars', 'int1', 2, true); COMMIT; ROLLBACK; +-- +-- +-- Test for case: pgv_set() created a regular variable and package with +-- (atxlevel=1, level=1). ROLLBACK changes this level to (atxlevel=0, level=0). +-- But ROLLBACK shouldn't change atxlevel in case rollback of sub-transaction. +-- +BEGIN; + BEGIN AUTONOMOUS; + SAVEPOINT sp1; + SELECT pgv_set('vars1', 'int1', 0); + ROLLBACK TO sp1; + COMMIT; +ROLLBACK; +SELECT pgv_remove('vars1', 'int1'); SELECT pgv_free(); From db204b08720f4157a4918dde1aa9c5f84b601cdf Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Fri, 27 Jan 2023 23:28:23 +0300 Subject: [PATCH 42/46] [PGPRO-7614] Add cosmetic changes and padding Tags: pg_variables --- pg_variables.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/pg_variables.c b/pg_variables.c index fd6e2f9..ab6149a 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -166,14 +166,14 @@ typedef struct tagVariableStatEntry Variable *variable; Package *package; Levels levels; - void **user_fctx; /* pointer to funcctx->user_fctx */ + void **user_fctx; /* pointer to funcctx->user_fctx */ } VariableStatEntry; typedef struct tagPackageStatEntry { HASH_SEQ_STATUS *status; Levels levels; - void **user_fctx; /* pointer to funcctx->user_fctx */ + void **user_fctx; /* pointer to funcctx->user_fctx */ } PackageStatEntry; #ifdef PGPRO_EE @@ -1391,8 +1391,9 @@ remove_package(PG_FUNCTION_ARGS) package = getPackage(package_name, true); /* - * Need to remove variables before packages because here calls hash_seq_term() - * which uses "entry->status->hashp->frozen" but memory context of "hashp" + * Need to remove variables before removing package because + * remove_variables_package() calls hash_seq_term() which uses + * "entry->status->hashp->frozen" but memory context of "hashp" * for regular variables can be deleted in removePackageInternal(). */ remove_variables_package(&variables_stats, package); @@ -1488,8 +1489,9 @@ remove_packages(PG_FUNCTION_ARGS) PG_RETURN_VOID(); /* - * Need to remove variables before packages because here calls hash_seq_term() - * which uses "entry->status->hashp->frozen" but memory context of "hashp" + * Need to remove variables before removing packages because + * remove_variables_all() calls hash_seq_term() which uses + * "entry->status->hashp->frozen" but memory context of "hashp" * for regular variables can be deleted in removePackageInternal(). */ remove_variables_all(&variables_stats); @@ -2266,9 +2268,10 @@ removeObject(TransObject *object, TransObjectType type) } /* - * Need to remove variables before state because here calls hash_seq_term() - * which uses "entry->status->hashp->frozen" but memory context of "hashp" - * for regular variables can be deleted in removeState()->freeValue(). + * Need to remove variables before removing state because + * remove_variables_variable() calls hash_seq_term() which uses + * "entry->status->hashp->frozen" but memory context of "hashp" + * for regular variables can be deleted in removeState() in freeValue(). */ /* Remove object from hash table */ hash_search(hash, object->name, HASH_REMOVE, &found); @@ -2358,8 +2361,8 @@ rollbackSavepoint(TransObject *object, TransObjectType type, bool sub) * Package inside autonomous transaction should not be detected * as 'object has been changed in upper level' because in this * case we will remove state in releaseSavepoint() but this - * state may be used pgvRestoreContext(). So atxlevel should - * be 0 in case rollback of autonomous transaction. + * state may be used in pgvRestoreContext(). So atxlevel should + * be 0 in case of rollback of autonomous transaction. */ GetActualState(object)->levels.atxlevel = sub ? getNestLevelATX() : 0; #endif From c7e55864dee0f10626fe6bfec654d0690e01d2f7 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Fri, 27 Jan 2023 19:44:55 +0300 Subject: [PATCH 43/46] [PGPRO-7287] New PgproRegisterXactCallback to filter by event kind Tags: pg_variables --- pg_variables.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pg_variables.c b/pg_variables.c index b1d1b47..633b029 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -2951,7 +2951,11 @@ _PG_init(void) NULL, NULL); +#if defined(PGPRO_EE) && (PG_VERSION_NUM >= 150000) + PgproRegisterXactCallback(pgvTransCallback, NULL, XACT_EVENT_KIND_VANILLA | XACT_EVENT_KIND_ATX); +#else RegisterXactCallback(pgvTransCallback, NULL); +#endif RegisterSubXactCallback(pgvSubTransCallback, NULL); /* Install hooks. */ From 16d0f974a1115935dbc1709b745d07d5de56b3a6 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Sat, 4 Feb 2023 00:39:05 +0300 Subject: [PATCH 44/46] [PGPRO-7742] Use PgproRegisterXactCallback for all EE-versions Tags: pg_variables --- pg_variables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pg_variables.c b/pg_variables.c index d87662c..1d3127f 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -2953,7 +2953,7 @@ _PG_init(void) NULL, NULL); -#if defined(PGPRO_EE) && (PG_VERSION_NUM >= 150000) +#ifdef PGPRO_EE PgproRegisterXactCallback(pgvTransCallback, NULL, XACT_EVENT_KIND_VANILLA | XACT_EVENT_KIND_ATX); #else RegisterXactCallback(pgvTransCallback, NULL); From 59f616e267053ca6ef76bef7634ab363c3796735 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Thu, 2 Mar 2023 20:28:20 +0300 Subject: [PATCH 45/46] [PGPRO-7856] Correction for object state releasing in case object was not deleted Tags: atx --- expected/pg_variables_atx_pkg.out | 35 ++++++++++++++++++++++++++ expected/pg_variables_atx_pkg_1.out | 39 +++++++++++++++++++++++++++++ pg_variables.c | 10 +++++--- pg_variables.h | 2 +- sql/pg_variables_atx_pkg.sql | 21 ++++++++++++++++ 5 files changed, 102 insertions(+), 5 deletions(-) diff --git a/expected/pg_variables_atx_pkg.out b/expected/pg_variables_atx_pkg.out index 527d5cc..e9c8412 100644 --- a/expected/pg_variables_atx_pkg.out +++ b/expected/pg_variables_atx_pkg.out @@ -436,3 +436,38 @@ SELECT pgv_free(); (1 row) +-- +-- +-- PGPRO-7856 +-- Test for case: we don't remove the package object without any variables at +-- the end of autonomous transaction but need to move the state of this object +-- to upper level. +-- +BEGIN; + BEGIN AUTONOMOUS; + SAVEPOINT sp1; + SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); + pgv_set +--------- + +(1 row) + + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + RELEASE sp1; + ROLLBACK; + BEGIN AUTONOMOUS; + SAVEPOINT sp2; + SAVEPOINT sp3; + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + COMMIT; +ROLLBACK; diff --git a/expected/pg_variables_atx_pkg_1.out b/expected/pg_variables_atx_pkg_1.out index d45c6ce..8e36d0a 100644 --- a/expected/pg_variables_atx_pkg_1.out +++ b/expected/pg_variables_atx_pkg_1.out @@ -474,3 +474,42 @@ SELECT pgv_free(); (1 row) +-- +-- +-- PGPRO-7856 +-- Test for case: we don't remove the package object without any variables at +-- the end of autonomous transaction but need to move the state of this object +-- to upper level. +-- +BEGIN; + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SAVEPOINT sp1; +ERROR: current transaction is aborted, commands ignored until end of transaction block + SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); +ERROR: current transaction is aborted, commands ignored until end of transaction block + SELECT pgv_free(); +ERROR: current transaction is aborted, commands ignored until end of transaction block + RELEASE sp1; +ERROR: current transaction is aborted, commands ignored until end of transaction block + ROLLBACK; + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" +LINE 1: BEGIN AUTONOMOUS; + ^ + SAVEPOINT sp2; +ERROR: SAVEPOINT can only be used in transaction blocks + SAVEPOINT sp3; +ERROR: SAVEPOINT can only be used in transaction blocks + SELECT pgv_free(); + pgv_free +---------- + +(1 row) + + COMMIT; +WARNING: there is no transaction in progress +ROLLBACK; +WARNING: there is no transaction in progress diff --git a/pg_variables.c b/pg_variables.c index b7b1302..c8ee939 100644 --- a/pg_variables.c +++ b/pg_variables.c @@ -2206,7 +2206,7 @@ removeState(TransObject *object, TransObjectType type, TransState *stateToDelete } /* Remove package or variable (either transactional or regular) */ -void +bool removeObject(TransObject *object, TransObjectType type) { bool found; @@ -2228,7 +2228,7 @@ removeObject(TransObject *object, TransObjectType type) if (getNestLevelATX() > 0 && !dlist_is_empty(&object->states)) { GetActualState(object)->is_valid = false; - return; + return false; } #endif @@ -2289,6 +2289,8 @@ removeObject(TransObject *object, TransObjectType type) } resetVariablesCache(); + + return true; } /* @@ -2429,8 +2431,8 @@ releaseSavepoint(TransObject *object, TransObjectType type, bool sub) dlist_is_empty(changesStack)) ) { - removeObject(object, type); - return; + if (removeObject(object, type)) + return; } /* diff --git a/pg_variables.h b/pg_variables.h index afa9b22..6508e9f 100644 --- a/pg_variables.h +++ b/pg_variables.h @@ -193,7 +193,7 @@ extern bool update_record(Variable *variable, HeapTupleHeader tupleHeader); extern bool delete_record(Variable *variable, Datum value, bool is_null); extern void insert_record_copy(RecordVar *dest_record, Datum src_tuple, Variable *variable); -extern void removeObject(TransObject *object, TransObjectType type); +extern bool removeObject(TransObject *object, TransObjectType type); #define GetActualState(object) \ (dlist_head_element(TransState, node, &((TransObject *) object)->states)) diff --git a/sql/pg_variables_atx_pkg.sql b/sql/pg_variables_atx_pkg.sql index a4a4943..49113d6 100644 --- a/sql/pg_variables_atx_pkg.sql +++ b/sql/pg_variables_atx_pkg.sql @@ -215,3 +215,24 @@ ROLLBACK; SELECT pgv_remove('vars1', 'int1'); SELECT pgv_free(); +-- +-- +-- PGPRO-7856 +-- Test for case: we don't remove the package object without any variables at +-- the end of autonomous transaction but need to move the state of this object +-- to upper level. +-- +BEGIN; + BEGIN AUTONOMOUS; + SAVEPOINT sp1; + SELECT pgv_set('vars2', 'any1', 'variable exists'::text, true); + SELECT pgv_free(); + RELEASE sp1; + ROLLBACK; + + BEGIN AUTONOMOUS; + SAVEPOINT sp2; + SAVEPOINT sp3; + SELECT pgv_free(); + COMMIT; +ROLLBACK; From fe2a1f6114bd21c9a0c2b967e7fc19d21e21ae7e Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Fri, 22 Sep 2023 12:47:12 +0300 Subject: [PATCH 46/46] travis-ci for v16 --- .travis.yml | 4 ++++ Dockerfile.tmpl | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 45189e8..80d5de7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,9 @@ notifications: on_failure: always env: + - PG_VERSION=16 LEVEL=nightmare + - PG_VERSION=16 LEVEL=hardcore + - PG_VERSION=16 - PG_VERSION=15 LEVEL=nightmare - PG_VERSION=15 LEVEL=hardcore - PG_VERSION=15 @@ -44,3 +47,4 @@ matrix: - env: PG_VERSION=13 LEVEL=nightmare - env: PG_VERSION=14 LEVEL=nightmare - env: PG_VERSION=15 LEVEL=nightmare + - env: PG_VERSION=16 LEVEL=nightmare diff --git a/Dockerfile.tmpl b/Dockerfile.tmpl index 0bcd176..2792b6e 100644 --- a/Dockerfile.tmpl +++ b/Dockerfile.tmpl @@ -6,7 +6,7 @@ RUN apk add --no-cache \ perl perl-ipc-run \ make musl-dev gcc bison flex coreutils \ zlib-dev libedit-dev linux-headers \ - clang clang-analyzer; + pkgconf icu-dev clang clang15 clang-analyzer; # Install fresh valgrind RUN apk add valgrind \ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy