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 \