From 1b59ad0ace80b04220da1ea7aa6a349a5a17b930 Mon Sep 17 00:00:00 2001 From: Mikhail Rutman Date: Tue, 26 Apr 2022 13:53:37 +0700 Subject: [PATCH 1/6] Porting multimaster to postgres 14 This commit ports multimaster to Postgres 14: - removed tablespace-setup from mmts/Makefile (according to commit 6c788d9f6aadb41d76a72d56149268371a7895ee); - add readOnlyTree flag to MtmProcessUtility() (according to commit 7c337b6b527b7052e6a751f966d5734c56f668b5); - explicitly specify the hash function HASH_STRING (according to commit b3817f5f774663d55931dd4fab9c5a94a15ae7ab); - refactor the use of EState (according to commit 1375422c7826a2bf387be29895e961614f69de4b); - add 'include_out_arguments' to the function FuncnameGetCandidates() (caccording to commit e56bce5d43789cce95d099554ae9593ada92b3b7); - use MyProc->xmin instead of MyPgXact->xmin in dmq.c (according to commit 73487a60fc1063ba4b5178b69aee4ee210c182c4); - remove EE pooler support; - use SearchNamedReplicationSlot() instead of ReplicationSlotAcquire() --- Cluster.pm | 1 + Makefile | 1 - expected/regression_ee.diff | 1887 +++++++++++++++++++++++++++++++++-- src/ddl.c | 47 +- src/dmq.c | 4 +- src/global_tx.c | 2 +- src/include/compat.h | 10 - src/pglogical_apply.c | 28 +- src/pglogical_output.c | 48 +- src/state.c | 32 +- 10 files changed, 1923 insertions(+), 137 deletions(-) diff --git a/Cluster.pm b/Cluster.pm index ea7860f695..5b68eb23c1 100644 --- a/Cluster.pm +++ b/Cluster.pm @@ -141,6 +141,7 @@ sub init { $node->init(allows_streaming => 'logical'); $node->append_conf('postgresql.conf', qq{ + enable_self_join_removal = off max_connections = 50 log_line_prefix = '%m [%p] [xid%x] %i ' log_statement = all diff --git a/Makefile b/Makefile index 994e04ff8a..19171ffacc 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,6 @@ all: multimaster.so submake-regress: $(MAKE) -C $(top_builddir)/src/test/regress all - $(MAKE) -C $(top_builddir)/src/test/regress tablespace-setup # all .pl tests should pass now, but let's see what the buildfarm says # ifndef MTM_ALL diff --git a/expected/regression_ee.diff b/expected/regression_ee.diff index ebc60ab969..24c5d720fb 100644 --- a/expected/regression_ee.diff +++ b/expected/regression_ee.diff @@ -1,3 +1,17 @@ +diff ../../../src/test/regress/expected/type_sanity.out ../tmp_check/regress_outdir/results/type_sanity.out +--- ../../../src/test/regress/expected/type_sanity.out CENSORED ++++ ../tmp_check/regress_outdir/results/type_sanity.out CENSORED +@@ -77,7 +77,9 @@ + 5017 | pg_mcv_list + 13374 | abstime + 13375 | reltime +-(8 rows) ++ 16514 | pg_publication ++ 16518 | pg_subscription ++(10 rows) + + -- Make sure typarray points to a "true" array type of our own base + SELECT p1.oid, p1.typname as basetype, p2.typname as arraytype, diff ../../../src/test/regress/expected/create_table.out ../tmp_check/regress_outdir/results/create_table.out --- ../../../src/test/regress/expected/create_table.out CENSORED +++ ../tmp_check/regress_outdir/results/create_table.out CENSORED @@ -29,7 +43,7 @@ diff ../../../src/test/regress/expected/create_table.out ../tmp_check/regress_ou diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_outdir/results/create_index.out --- ../../../src/test/regress/expected/create_index.out CENSORED +++ ../tmp_check/regress_outdir/results/create_index.out CENSORED -@@ -1394,31 +1394,33 @@ +@@ -1371,31 +1371,33 @@ CREATE TABLE concur_heap (f1 text, f2 text); -- empty table CREATE INDEX CONCURRENTLY concur_index1 ON concur_heap(f2,f1); @@ -70,7 +84,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou COMMIT; -- test where predicate is able to do a transactional update during -- a concurrent build before switching pg_index state flags. -@@ -1430,7 +1432,9 @@ +@@ -1407,7 +1409,9 @@ END; $$; CREATE INDEX CONCURRENTLY concur_index8 ON concur_heap (f1) WHERE predicate_stable(); @@ -80,7 +94,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou DROP FUNCTION predicate_stable(); -- But you can do a regular index build in a transaction BEGIN; -@@ -1439,8 +1443,6 @@ +@@ -1416,8 +1420,6 @@ -- Failed builds are left invalid by VACUUM FULL, fixed by REINDEX VACUUM FULL concur_heap; REINDEX TABLE concur_heap; @@ -89,7 +103,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou DELETE FROM concur_heap WHERE f1 = 'b'; VACUUM FULL concur_heap; \d concur_heap -@@ -1450,12 +1452,6 @@ +@@ -1427,12 +1429,6 @@ f1 | text | | | f2 | text | | | Indexes: @@ -102,7 +116,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou "std_index" btree (f2) REINDEX TABLE concur_heap; -@@ -1466,12 +1462,6 @@ +@@ -1443,12 +1439,6 @@ f1 | text | | | f2 | text | | | Indexes: @@ -115,7 +129,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou "std_index" btree (f2) -- Temporary tables with concurrent builds and on-commit actions -@@ -1481,7 +1471,9 @@ +@@ -1458,7 +1448,9 @@ ON COMMIT PRESERVE ROWS; INSERT INTO concur_temp VALUES (1, 'foo'), (2, 'bar'); CREATE INDEX CONCURRENTLY concur_temp_ind ON concur_temp(f1); @@ -125,7 +139,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou DROP TABLE concur_temp; -- ON COMMIT DROP BEGIN; -@@ -1490,34 +1482,42 @@ +@@ -1467,34 +1459,42 @@ INSERT INTO concur_temp VALUES (1, 'foo'), (2, 'bar'); -- Fails when running in a transaction. CREATE INDEX CONCURRENTLY concur_temp_ind ON concur_temp(f1); @@ -172,7 +186,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou \d concur_heap Table "public.concur_heap" Column | Type | Collation | Nullable | Default -@@ -2474,46 +2474,38 @@ +@@ -2583,46 +2583,38 @@ INSERT INTO concur_reindex_tab4 VALUES (1), (1), (2); -- This trick creates an invalid index. CREATE UNIQUE INDEX CONCURRENTLY concur_reindex_ind5 ON concur_reindex_tab4 (c1); @@ -260,6 +274,687 @@ diff ../../../src/test/regress/expected/index_including_gist.out ../tmp_check/re DROP TABLE tbl_gist; /* +diff ../../../src/test/regress/expected/profiles.out ../tmp_check/regress_outdir/results/profiles.out +--- ../../../src/test/regress/expected/profiles.out CENSORED ++++ ../tmp_check/regress_outdir/results/profiles.out CENSORED +@@ -21,16 +21,15 @@ + PASSWORD_REUSE_TIME 1 + PASSWORD_REUSE_MAX 1 + PASSWORD_GRACE_TIME 1; ++ERROR: [MTM] failed to prepare transaction at peer node + ALTER ROLE regress_profile_role PROFILE regress_test_profile; ++ERROR: profile "regress_test_profile" does not exist + DROP PROFILE regress_test_profile; -- error +-ERROR: profile "regress_test_profile" cannot be dropped because some objects depend on it +-DETAIL: profile of role regress_profile_role ++ERROR: profile "regress_test_profile" does not exist + -- Test profile parameters + ALTER PROFILE regress_test_profile LIMIT + FAILED_LOGIN_ATTEMPTS 0; -- error +-ERROR: invalid resource limit +-LINE 2: FAILED_LOGIN_ATTEMPTS 0; +- ^ ++ERROR: profile "regress_test_profile" does not exist + ALTER PROFILE regress_test_profile LIMIT + FAILED_LOGIN_ATTEMPTS 1.1; -- error + ERROR: syntax error at or near "1.1" +@@ -38,9 +37,7 @@ + ^ + ALTER PROFILE regress_test_profile LIMIT + PASSWORD_REUSE_TIME -2; -- error +-ERROR: invalid resource limit +-LINE 2: PASSWORD_REUSE_TIME -2; +- ^ ++ERROR: profile "regress_test_profile" does not exist + ALTER PROFILE regress_test_profile LIMIT + PASSWORD_REUSE_MAX -1; -- error + ERROR: syntax error at or near "-" +@@ -48,12 +45,16 @@ + ^ + ALTER PROFILE regress_test_profile LIMIT + PASSWORD_LIFE_TIME 0.1; ++ERROR: profile "regress_test_profile" does not exist + ALTER PROFILE regress_test_profile LIMIT + PASSWORD_GRACE_TIME default; ++ERROR: profile "regress_test_profile" does not exist + ALTER PROFILE regress_test_profile LIMIT + FAILED_LOGIN_ATTEMPTS unlimited; ++ERROR: profile "regress_test_profile" does not exist + ALTER PROFILE regress_test_profile LIMIT + PASSWORD_REUSE_TIME 1; ++ERROR: profile "regress_test_profile" does not exist + -- Use ORDER BY pflname in order to make test results not dependable on possible + -- changes in records restoring order + SELECT +@@ -69,15 +70,15 @@ + pflpasswordminlen, + pflpasswordrequirecomplex + FROM pg_profile ORDER BY pflname; +- pflname | pflfailedloginattempts | pflfailedauthkeeptime | pfluserinactivetime | pflpasswordreusetime | pflpasswordreusemax | pflpasswordlifetime | pflpasswordgracetime | pflpasswordminuniqchars | pflpasswordminlen | pflpasswordrequirecomplex +-----------------------+------------------------+-----------------------+---------------------+----------------------+---------------------+---------------------+----------------------+-------------------------+-------------------+--------------------------- +- default | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | 0 +- regress_test_profile | -1 | -2 | -2 | 86400 | 1 | 8640 | -2 | -2 | -2 | -2 +-(2 rows) ++ pflname | pflfailedloginattempts | pflfailedauthkeeptime | pfluserinactivetime | pflpasswordreusetime | pflpasswordreusemax | pflpasswordlifetime | pflpasswordgracetime | pflpasswordminuniqchars | pflpasswordminlen | pflpasswordrequirecomplex ++---------+------------------------+-----------------------+---------------------+----------------------+---------------------+---------------------+----------------------+-------------------------+-------------------+--------------------------- ++ default | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | 0 ++(1 row) + + -- Cleanup + ALTER ROLE regress_profile_role PROFILE DEFAULT; + DROP PROFILE regress_test_profile; ++ERROR: profile "regress_test_profile" does not exist + DROP ROLE regress_profile_role; + -- Check that the parameters USER_INACTIVE_TIME, FAILED_AUTH_KEEP_TIME and + -- PASSWORD_LIFE_TIME can't take value 0. Test both cases when these parameters +@@ -101,22 +102,18 @@ + USER_INACTIVE_TIME 1 + FAILED_AUTH_KEEP_TIME 1 + PASSWORD_LIFE_TIME 1; ++ERROR: [MTM] failed to prepare transaction at peer node + -- error, USER_INACTIVE_TIME can't take zero value + ALTER PROFILE regress_test_profile LIMIT USER_INACTIVE_TIME 0; +-ERROR: invalid resource limit +-LINE 1: ALTER PROFILE regress_test_profile LIMIT USER_INACTIVE_TIME ... +- ^ ++ERROR: profile "regress_test_profile" does not exist + -- error, FAILED_AUTH_KEEP_TIME can't take zero value + ALTER PROFILE regress_test_profile LIMIT FAILED_AUTH_KEEP_TIME 0; +-ERROR: invalid resource limit +-LINE 1: ALTER PROFILE regress_test_profile LIMIT FAILED_AUTH_KEEP_TI... +- ^ ++ERROR: profile "regress_test_profile" does not exist + -- error, PASSWORD_LIFE_TIME can't take zero value + ALTER PROFILE regress_test_profile LIMIT PASSWORD_LIFE_TIME 0; +-ERROR: invalid resource limit +-LINE 1: ALTER PROFILE regress_test_profile LIMIT PASSWORD_LIFE_TIME ... +- ^ ++ERROR: profile "regress_test_profile" does not exist + DROP PROFILE regress_test_profile; ++ERROR: profile "regress_test_profile" does not exist + -- + -- Test cases added within the task #PGPRO-3656 (Merge extra features of + -- passwordcheck under control of new passoword policy) +@@ -130,45 +127,54 @@ + PASSWORD_MIN_UNIQUE_CHARS 3 + PASSWORD_MIN_LEN 3 + PASSWORD_REQUIRE_COMPLEX 1; ++ERROR: [MTM] failed to prepare transaction at peer node + CREATE USER u1 PROFILE pfl1; ++ERROR: profile "pfl1" does not exist + -- ok, password string satisfies the limits PASSWORD_MIN_LEN, + -- PASSWORD_REQUIRE_COMPLEX and PASSWORD_MIN_UNIQUE_CHARS + ALTER USER u1 PASSWORD 'foo1'; ++ERROR: role "u1" does not exist + -- error, password string breaks the limit PASSWORD_MIN_LEN. + ALTER USER u1 PASSWORD 'fo'; +-ERROR: password must be at least 3 characters long ++ERROR: role "u1" does not exist + -- error, password string breaks the limit PASSWORD_REQUIRE_COMPLEX. + ALTER USER u1 PASSWORD 'fooo'; +-ERROR: password must contain both letters and nonletters ++ERROR: role "u1" does not exist + -- error, password string breaks the limit PASSWORD_MIN_UNIQUE_CHARS. + ALTER USER u1 PASSWORD 'f000'; +-ERROR: password must contain at least 3 unique characters ++ERROR: role "u1" does not exist + --error, password string contains a user name + ALTER USER u1 PASSWORD '123u1__'; +-ERROR: password must not contain user name ++ERROR: role "u1" does not exist + -- Turn off PASSWORD_REQUIRE_COMPLEX in order to allow acceptance of password + -- string containing only letters or digits + ALTER PROFILE pfl1 LIMIT PASSWORD_REQUIRE_COMPLEX 0; ++ERROR: profile "pfl1" does not exist + ALTER USER u1 PASSWORD 'foobar'; -- ok, password containing only letter is ++ERROR: role "u1" does not exist + -- now acceptable since the limit + -- PASSWORD_REQUIRE_COMPLEX was set to + -- false. + ALTER USER u1 PASSWORD '1234'; -- ok, by the same reason as for the password ++ERROR: role "u1" does not exist + -- string 'foobar' + -- Check that the limits PASSWORD_MIN_LEN, PASSWORD_MIN_UNIQUE_CHARS are still + -- followed when the limit PASSWORD_REQUIRE_COMPLEX is off + -- error, password string breaks the limit PASSWORD_MIN_LEN. + ALTER USER u1 PASSWORD 'fo'; +-ERROR: password must be at least 3 characters long ++ERROR: role "u1" does not exist + -- error, password string breaks the limit PASSWORD_MIN_UNIQUE_CHARS. + ALTER USER u1 PASSWORD 'foo'; +-ERROR: password must contain at least 3 unique characters ++ERROR: role "u1" does not exist + -- Check that a user name can be specified as a part of password phrase + ALTER USER u1 PASSWORD '123u1__'; --ok, it is allowed to specify a password ++ERROR: role "u1" does not exist + -- string containing a user name + -- Clean up + DROP USER u1; ++ERROR: role "u1" does not exist + DROP PROFILE pfl1; ++ERROR: profile "pfl1" does not exist + -- Check that a value for clauses PASSWORD_MIN_UNIQUE_CHARS and PASSWORD_MIN_LEN + -- is positive integer + -- error, value of PASSWORD_MIN_UNIQUE_CHARS must be > 0 +@@ -192,16 +198,13 @@ + LINE 1: CREATE PROFILE pfl1 LIMIT PASSWORD_MIN_LEN 1.2; + ^ + CREATE PROFILE pfl1; ++ERROR: [MTM] failed to prepare transaction at peer node + -- error, value of PASSWORD_MIN_UNIQUE_CHARS must be > 0 + ALTER PROFILE pfl1 LIMIT PASSWORD_MIN_UNIQUE_CHARS 0; +-ERROR: invalid resource limit +-LINE 1: ALTER PROFILE pfl1 LIMIT PASSWORD_MIN_UNIQUE_CHARS 0; +- ^ ++ERROR: profile "pfl1" does not exist + -- error, value of PASSWORD_MIN_LEN must be > 0 + ALTER PROFILE pfl1 LIMIT PASSWORD_MIN_LEN 0; +-ERROR: invalid resource limit +-LINE 1: ALTER PROFILE pfl1 LIMIT PASSWORD_MIN_LEN 0; +- ^ ++ERROR: profile "pfl1" does not exist + -- error, value of PASSWORD_MIN_UNIQUE_CHARS must be integer + ALTER PROFILE pfl1 LIMIT PASSWORD_MIN_UNIQUE_CHARS 1.2; + ERROR: syntax error at or near "1.2" +@@ -214,17 +217,26 @@ + ^ + -- Clean up + DROP PROFILE pfl1; ++ERROR: profile "pfl1" does not exist + -- Check that boolean value for the clause PASSWORD_REQUIRE_COMPLEX can take any + -- of the following values: ON, OFF, TRUE, FALSE, 1, 0 + CREATE PROFILE pfl1; ++ERROR: [MTM] failed to prepare transaction at peer node + ALTER PROFILE pfl1 LIMIT PASSWORD_REQUIRE_COMPLEX 0; -- ok ++ERROR: profile "pfl1" does not exist + ALTER PROFILE pfl1 LIMIT PASSWORD_REQUIRE_COMPLEX 1; -- ok ++ERROR: profile "pfl1" does not exist + ALTER PROFILE pfl1 LIMIT PASSWORD_REQUIRE_COMPLEX false; -- ok ++ERROR: profile "pfl1" does not exist + ALTER PROFILE pfl1 LIMIT PASSWORD_REQUIRE_COMPLEX true; -- ok ++ERROR: profile "pfl1" does not exist + ALTER PROFILE pfl1 LIMIT PASSWORD_REQUIRE_COMPLEX on; -- ok ++ERROR: profile "pfl1" does not exist + ALTER PROFILE pfl1 LIMIT PASSWORD_REQUIRE_COMPLEX off; -- ok ++ERROR: profile "pfl1" does not exist + -- Clean up + DROP PROFILE pfl1; ++ERROR: profile "pfl1" does not exist + -- Check that the error "ERROR: conflicting or redundant resource" is emitted + -- in case one of the options PASSWORD_MIN_UNIQUE_CHARS, PASSWORD_MIN_LEN, + -- PASSWORD_REQUIRE_COMPLEX repeated twice. +@@ -244,20 +256,15 @@ + ^ + -- The same test for ALTER PROFILE + CREATE PROFILE pfl1; ++ERROR: [MTM] failed to prepare transaction at peer node + ALTER PROFILE pfl1 LIMIT PASSWORD_MIN_LEN 2 PASSWORD_MIN_LEN 1; -- error +-ERROR: conflicting or redundant resource +-LINE 1: ALTER PROFILE pfl1 LIMIT PASSWORD_MIN_LEN 2 PASSWORD_MIN_LEN... +- ^ ++ERROR: profile "pfl1" does not exist + ALTER PROFILE pfl1 + LIMIT PASSWORD_MIN_UNIQUE_CHARS 2 PASSWORD_MIN_UNIQUE_CHARS 1; -- error +-ERROR: conflicting or redundant resource +-LINE 2: LIMIT PASSWORD_MIN_UNIQUE_CHARS 2 PASSWORD_MIN_UNIQUE_CHARS ... +- ^ ++ERROR: profile "pfl1" does not exist + ALTER PROFILE pfl1 + LIMIT PASSWORD_REQUIRE_COMPLEX off PASSWORD_REQUIRE_COMPLEX on; -- error +-ERROR: conflicting or redundant resource +-LINE 2: LIMIT PASSWORD_REQUIRE_COMPLEX off PASSWORD_REQUIRE_COMPLEX ... +- ^ ++ERROR: profile "pfl1" does not exist + -- Unlike other profile options, PASSWORD_REQUIRE_COMPLEX cannot be set to + -- UNLIMITED. + ALTER PROFILE pfl1 LIMIT PASSWORD_REQUIRE_COMPLEX UNLIMITED; +@@ -266,56 +273,58 @@ + ^ + -- Clean up + DROP PROFILE pfl1; ++ERROR: profile "pfl1" does not exist + -- Begin of tests that were added within implementation of the task PGPRO-4309 + -- Check that ALTER PROFILE RENAME does work as expected. + CREATE PROFILE profile_test; ++ERROR: [MTM] failed to prepare transaction at peer node + -- Query what profiles are currently stored in the system catalog table 'pg_profile'. + -- Use ORDER BY pflname in order to make test results not dependable on possible + -- changes in records restoring order + SELECT pflname FROM pg_profile ORDER BY pflname; +- pflname +--------------- ++ pflname ++--------- + default +- profile_test +-(2 rows) ++(1 row) + + -- Rename profile 'profile_test' to 'profile_test_new' + ALTER PROFILE profile_test RENAME TO profile_test_new; ++ERROR: profile "profile_test" does not exist + -- and check that the new profile name is stored in + -- the system catalog table pg_profile + SELECT pflname FROM pg_profile ORDER BY pflname; +- pflname +------------------- ++ pflname ++--------- + default +- profile_test_new +-(2 rows) ++(1 row) + + -- Clean up + DROP PROFILE profile_test_new; ++ERROR: profile "profile_test_new" does not exist + -- Check that rounding of a time value is correct + CREATE PROFILE test_profile LIMIT PASSWORD_LIFE_TIME 0.00001; ++ERROR: [MTM] failed to prepare transaction at peer node + ALTER PROFILE test_profile LIMIT PASSWORD_LIFE_TIME 0.0000000000000000000000000000000001; +-ERROR: invalid resource limit +-LINE 1: ALTER PROFILE test_profile LIMIT PASSWORD_LIFE_TIME 0.000000... +- ^ ++ERROR: profile "test_profile" does not exist + SELECT pflpasswordlifetime FROM pg_profile WHERE pflname = 'test_profile'; + pflpasswordlifetime + --------------------- +- 1 +-(1 row) ++(0 rows) + + -- Check that PASSWORD_GRACE_TIME can be assigned the value 0; + ALTER PROFILE test_profile LIMIT PASSWORD_GRACE_TIME 0 PASSWORD_LIFE_TIME 1; ++ERROR: profile "test_profile" does not exist + SELECT pflpasswordgracetime, pflpasswordlifetime FROM pg_profile WHERE pflname = 'test_profile'; + pflpasswordgracetime | pflpasswordlifetime + ----------------------+--------------------- +- 0 | 86400 +-(1 row) ++(0 rows) + + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + -- Check that a value of interval type can be supplied for time-related profile options in + -- the statement CREATE PROFILE + CREATE PROFILE test_profile LIMIT PASSWORD_LIFE_TIME INTERVAL '1' DAY PASSWORD_GRACE_TIME INTERVAL '2' HOUR PASSWORD_REUSE_TIME INTERVAL '30' MINUTE USER_INACTIVE_TIME INTERVAL '75' SECOND ; ++ERROR: [MTM] failed to prepare transaction at peer node + SELECT + pflpasswordlifetime, + pflpasswordgracetime, +@@ -324,13 +333,14 @@ + FROM pg_profile WHERE pflname='test_profile'; + pflpasswordlifetime | pflpasswordgracetime | pflpasswordreusetime | pfluserinactivetime + ---------------------+----------------------+----------------------+--------------------- +- 86400 | 7200 | 1800 | 75 +-(1 row) ++(0 rows) + + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + -- Check that a value of interval type can be supplied in all supported formats + -- the statement CREATE PROFILE + CREATE PROFILE test_profile LIMIT FAILED_AUTH_KEEP_TIME INTERVAL '1 YEAR 2 MONTHS 3 DAYS 4 HOURS 5 MINUTES 6.123 SECONDS' PASSWORD_LIFE_TIME INTERVAL '1 MINUTE' MINUTE PASSWORD_GRACE_TIME INTERVAL '1 SECOND' MINUTE PASSWORD_REUSE_TIME INTERVAL '1 MINUTE 1 SECOND' SECOND USER_INACTIVE_TIME INTERVAL '1 MINUTE 1 SECOND' MINUTE; ++ERROR: [MTM] failed to prepare transaction at peer node + SELECT + pflfailedauthkeeptime, + pflpasswordlifetime, +@@ -340,11 +350,12 @@ + FROM pg_profile WHERE pflname='test_profile'; + pflfailedauthkeeptime | pflpasswordlifetime | pflpasswordgracetime | pflpasswordreusetime | pfluserinactivetime + -----------------------+---------------------+----------------------+----------------------+--------------------- +- 37015506 | 60 | 0 | 61 | 60 +-(1 row) ++(0 rows) + + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + CREATE PROFILE test_profile LIMIT FAILED_AUTH_KEEP_TIME INTERVAL '1 YEAR 2 MONTHS 3 DAYS 4 HOURS 5 MINUTES 6.523 SECONDS' PASSWORD_LIFE_TIME INTERVAL '1 MINUTE' SECOND PASSWORD_GRACE_TIME INTERVAL '1 MINUTE' PASSWORD_REUSE_TIME INTERVAL '1-2' SECOND USER_INACTIVE_TIME INTERVAL '3 4:05:06' SECOND; ++ERROR: [MTM] failed to prepare transaction at peer node + SELECT + pflfailedauthkeeptime, + pflpasswordlifetime, +@@ -354,21 +365,22 @@ + FROM pg_profile WHERE pflname='test_profile'; + pflfailedauthkeeptime | pflpasswordlifetime | pflpasswordgracetime | pflpasswordreusetime | pfluserinactivetime + -----------------------+---------------------+----------------------+----------------------+--------------------- +- 37015507 | 60 | 60 | 36741600 | 273906 +-(1 row) ++(0 rows) + + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + CREATE PROFILE test_profile LIMIT PASSWORD_REUSE_TIME INTERVAL 'P2Y3M4DT5H6M7S' USER_INACTIVE_TIME INTERVAL 'P0003-04-05T06:07:08'; ++ERROR: [MTM] failed to prepare transaction at peer node + SELECT + pflpasswordreusetime, + pfluserinactivetime + FROM pg_profile WHERE pflname='test_profile'; + pflpasswordreusetime | pfluserinactivetime + ----------------------+--------------------- +- 71255167 | 105494828 +-(1 row) ++(0 rows) + + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + -- Invalid interval type values + -- the statement CREATE PROFILE + --FAILED_AUTH_KEEP_TIME value must be from 1 to 2147483647 seconds +@@ -419,6 +431,7 @@ + -- Check that an interval type value and a real type value can intermixed + -- in the same CREATE PROFILE statement. + CREATE PROFILE test_profile LIMIT PASSWORD_LIFE_TIME INTERVAL '1' DAY PASSWORD_GRACE_TIME 0.01 PASSWORD_REUSE_TIME INTERVAL '30' MINUTE USER_INACTIVE_TIME 1; ++ERROR: [MTM] failed to prepare transaction at peer node + SELECT + pflpasswordlifetime, + pflpasswordgracetime, +@@ -427,14 +440,16 @@ + FROM pg_profile WHERE pflname='test_profile'; + pflpasswordlifetime | pflpasswordgracetime | pflpasswordreusetime | pfluserinactivetime + ---------------------+----------------------+----------------------+--------------------- +- 86400 | 864 | 1800 | 86400 +-(1 row) ++(0 rows) + + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + CREATE PROFILE test_profile; ++ERROR: [MTM] failed to prepare transaction at peer node + -- Check that a value of interval type can be supplied for time-related profile options in + -- the statement ALTER PROFILE + ALTER PROFILE test_profile LIMIT PASSWORD_LIFE_TIME INTERVAL '1' DAY PASSWORD_GRACE_TIME INTERVAL '2' HOUR PASSWORD_REUSE_TIME INTERVAL '30' MINUTE USER_INACTIVE_TIME INTERVAL '75' SECOND ; ++ERROR: profile "test_profile" does not exist + SELECT + pflpasswordlifetime, + pflpasswordgracetime, +@@ -443,12 +458,12 @@ + FROM pg_profile WHERE pflname='test_profile'; + pflpasswordlifetime | pflpasswordgracetime | pflpasswordreusetime | pfluserinactivetime + ---------------------+----------------------+----------------------+--------------------- +- 86400 | 7200 | 1800 | 75 +-(1 row) ++(0 rows) + + -- Check that a value of interval type can be supplied in all supported formats + -- the statement ALTER PROFILE + ALTER PROFILE test_profile LIMIT FAILED_AUTH_KEEP_TIME INTERVAL '1 YEAR 2 MONTHS 3 DAYS 4 HOURS 5 MINUTES 6.123 SECONDS' PASSWORD_LIFE_TIME INTERVAL '1 MINUTE' MINUTE PASSWORD_GRACE_TIME INTERVAL '1 SECOND' MINUTE PASSWORD_REUSE_TIME INTERVAL '1 MINUTE 1 SECOND' SECOND USER_INACTIVE_TIME INTERVAL '1 MINUTE 1 SECOND' MINUTE; ++ERROR: profile "test_profile" does not exist + SELECT + pflfailedauthkeeptime, + pflpasswordlifetime, +@@ -458,10 +473,10 @@ + FROM pg_profile WHERE pflname='test_profile'; + pflfailedauthkeeptime | pflpasswordlifetime | pflpasswordgracetime | pflpasswordreusetime | pfluserinactivetime + -----------------------+---------------------+----------------------+----------------------+--------------------- +- 37015506 | 60 | 0 | 61 | 60 +-(1 row) ++(0 rows) + + ALTER PROFILE test_profile LIMIT FAILED_AUTH_KEEP_TIME INTERVAL '1 YEAR 2 MONTHS 3 DAYS 4 HOURS 5 MINUTES 6.523 SECONDS' PASSWORD_LIFE_TIME INTERVAL '1 MINUTE' SECOND PASSWORD_GRACE_TIME INTERVAL '1 MINUTE' PASSWORD_REUSE_TIME INTERVAL '1-2' SECOND USER_INACTIVE_TIME INTERVAL '3 4:05:06' SECOND; ++ERROR: profile "test_profile" does not exist + SELECT + pflfailedauthkeeptime, + pflpasswordlifetime, +@@ -471,69 +486,49 @@ + FROM pg_profile WHERE pflname='test_profile'; + pflfailedauthkeeptime | pflpasswordlifetime | pflpasswordgracetime | pflpasswordreusetime | pfluserinactivetime + -----------------------+---------------------+----------------------+----------------------+--------------------- +- 37015507 | 60 | 60 | 36741600 | 273906 +-(1 row) ++(0 rows) + + ALTER PROFILE test_profile LIMIT PASSWORD_REUSE_TIME INTERVAL 'P2Y3M4DT5H6M7S' USER_INACTIVE_TIME INTERVAL 'P0003-04-05T06:07:08'; ++ERROR: profile "test_profile" does not exist + SELECT + pflpasswordreusetime, + pfluserinactivetime + FROM pg_profile WHERE pflname='test_profile'; + pflpasswordreusetime | pfluserinactivetime + ----------------------+--------------------- +- 71255167 | 105494828 +-(1 row) ++(0 rows) + + -- Invalid interval type values + -- the statement ALTER PROFILE + --FAILED_AUTH_KEEP_TIME value must be from 1 to 2147483647 seconds + ALTER PROFILE test_profile LIMIT FAILED_AUTH_KEEP_TIME INTERVAL '100' YEAR; --error +-ERROR: interval must be in range 1..2147483647 seconds +-LINE 1: ...test_profile LIMIT FAILED_AUTH_KEEP_TIME INTERVAL '100' YEAR... +- ^ ++ERROR: profile "test_profile" does not exist + ALTER PROFILE test_profile LIMIT FAILED_AUTH_KEEP_TIME INTERVAL '1 MINUTE' DAY; --error +-ERROR: interval must be in range 1..2147483647 seconds +-LINE 1: ...test_profile LIMIT FAILED_AUTH_KEEP_TIME INTERVAL '1 MINUTE'... +- ^ ++ERROR: profile "test_profile" does not exist + --PASSWORD_LIFE_TIME value must be from 1 to 2147483647 seconds + ALTER PROFILE test_profile LIMIT PASSWORD_LIFE_TIME INTERVAL '100' YEAR; --error +-ERROR: interval must be in range 1..2147483647 seconds +-LINE 1: ...LE test_profile LIMIT PASSWORD_LIFE_TIME INTERVAL '100' YEAR... +- ^ ++ERROR: profile "test_profile" does not exist + ALTER PROFILE test_profile LIMIT PASSWORD_LIFE_TIME INTERVAL '1 MINUTE' HOUR; --error +-ERROR: interval must be in range 1..2147483647 seconds +-LINE 1: ...LE test_profile LIMIT PASSWORD_LIFE_TIME INTERVAL '1 MINUTE'... +- ^ ++ERROR: profile "test_profile" does not exist + --PASSWORD_GRACE_TIME value must be from 0 to 2147483647 seconds + ALTER PROFILE test_profile LIMIT PASSWORD_GRACE_TIME INTERVAL '100' YEAR; --error +-ERROR: interval must be in range 0..2147483647 seconds +-LINE 1: ...E test_profile LIMIT PASSWORD_GRACE_TIME INTERVAL '100' YEAR... +- ^ ++ERROR: profile "test_profile" does not exist + ALTER PROFILE test_profile LIMIT PASSWORD_GRACE_TIME INTERVAL '-1 SECOND'; --error +-ERROR: interval must be in range 0..2147483647 seconds +-LINE 1: ...E test_profile LIMIT PASSWORD_GRACE_TIME INTERVAL '-1 SECOND... +- ^ ++ERROR: profile "test_profile" does not exist + --PASSWORD_REUSE_TIME value must be from 0 to 2147483647 seconds + ALTER PROFILE test_profile LIMIT PASSWORD_REUSE_TIME INTERVAL '100' YEAR; --error +-ERROR: interval must be in range 0..2147483647 seconds +-LINE 1: ...E test_profile LIMIT PASSWORD_REUSE_TIME INTERVAL '100' YEAR... +- ^ ++ERROR: profile "test_profile" does not exist + ALTER PROFILE test_profile LIMIT PASSWORD_REUSE_TIME INTERVAL '-1 SECOND'; --error +-ERROR: interval must be in range 0..2147483647 seconds +-LINE 1: ...E test_profile LIMIT PASSWORD_REUSE_TIME INTERVAL '-1 SECOND... +- ^ ++ERROR: profile "test_profile" does not exist + --USER_INACTIVE_TIME value must be from 1 to 2147483647 seconds + ALTER PROFILE test_profile LIMIT USER_INACTIVE_TIME INTERVAL '100' YEAR; --error +-ERROR: interval must be in range 1..2147483647 seconds +-LINE 1: ...LE test_profile LIMIT USER_INACTIVE_TIME INTERVAL '100' YEAR... +- ^ ++ERROR: profile "test_profile" does not exist + ALTER PROFILE test_profile LIMIT USER_INACTIVE_TIME INTERVAL '1 SECOND' YEAR; --error +-ERROR: interval must be in range 1..2147483647 seconds +-LINE 1: ...LE test_profile LIMIT USER_INACTIVE_TIME INTERVAL '1 SECOND'... +- ^ ++ERROR: profile "test_profile" does not exist + -- Check that an interval type value and a real type value can intermixed + -- in the same ALTER PROFILE statement. + ALTER PROFILE test_profile LIMIT PASSWORD_LIFE_TIME INTERVAL '5' DAY PASSWORD_GRACE_TIME 0.01 PASSWORD_REUSE_TIME INTERVAL '70' MINUTE USER_INACTIVE_TIME 1; ++ERROR: profile "test_profile" does not exist + SELECT + pflpasswordlifetime, + pflpasswordgracetime, +@@ -542,36 +537,40 @@ + FROM pg_profile WHERE pflname='test_profile'; + pflpasswordlifetime | pflpasswordgracetime | pflpasswordreusetime | pfluserinactivetime + ---------------------+----------------------+----------------------+--------------------- +- 432000 | 864 | 4200 | 86400 +-(1 row) ++(0 rows) + + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + -- Check support of statement CREATE PROFILE IF NOT EXISTS + CREATE PROFILE IF NOT EXISTS test_profile; ++ERROR: [MTM] failed to prepare transaction at peer node + -- Check that the profile test_profile was created + SELECT 1 FROM pg_profile WHERE pflname='test_profile'; + ?column? + ---------- +- 1 +-(1 row) ++(0 rows) + + -- Re-execute the same CREATE PROFILE statement and check it doesn't fail + CREATE PROFILE IF NOT EXISTS test_profile; ++ERROR: [MTM] failed to prepare transaction at peer node + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + -- Check support of statement CREATE PROFILE FROM + CREATE PROFILE test_profile LIMIT PASSWORD_LIFE_TIME INTERVAL '10' HOUR FAILED_LOGIN_ATTEMPTS 7; ++ERROR: [MTM] failed to prepare transaction at peer node + CREATE PROFILE test_profile_copy FROM test_profile; ++ERROR: profile "test_profile" does not exist + -- Use ORDER BY pflname in order to make test results not dependable on possible + -- changes in records restoring order + SELECT pflname, pflfailedloginattempts, pflfailedauthkeeptime, pfluserinactivetime, pflpasswordreusetime, pflpasswordreusemax, pflpasswordlifetime, pflpasswordgracetime, pflpasswordminuniqchars, pflpasswordminlen, pflpasswordrequirecomplex FROM pg_profile WHERE pflname IN ('test_profile', 'test_profile_copy') ORDER BY pflname; +- pflname | pflfailedloginattempts | pflfailedauthkeeptime | pfluserinactivetime | pflpasswordreusetime | pflpasswordreusemax | pflpasswordlifetime | pflpasswordgracetime | pflpasswordminuniqchars | pflpasswordminlen | pflpasswordrequirecomplex +--------------------+------------------------+-----------------------+---------------------+----------------------+---------------------+---------------------+----------------------+-------------------------+-------------------+--------------------------- +- test_profile | 7 | -2 | -2 | -2 | -2 | 36000 | -2 | -2 | -2 | -2 +- test_profile_copy | 7 | -2 | -2 | -2 | -2 | 36000 | -2 | -2 | -2 | -2 +-(2 rows) ++ pflname | pflfailedloginattempts | pflfailedauthkeeptime | pfluserinactivetime | pflpasswordreusetime | pflpasswordreusemax | pflpasswordlifetime | pflpasswordgracetime | pflpasswordminuniqchars | pflpasswordminlen | pflpasswordrequirecomplex ++---------+------------------------+-----------------------+---------------------+----------------------+---------------------+---------------------+----------------------+-------------------------+-------------------+--------------------------- ++(0 rows) + + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + DROP PROFILE test_profile_copy; ++ERROR: profile "test_profile_copy" does not exist + -- Check that all profile options support the value DEFAULT. + CREATE PROFILE test_profile LIMIT + FAILED_LOGIN_ATTEMPTS DEFAULT +@@ -584,6 +583,7 @@ + PASSWORD_MIN_UNIQUE_CHARS DEFAULT + PASSWORD_MIN_LEN DEFAULT + PASSWORD_REQUIRE_COMPLEX DEFAULT; ++ERROR: [MTM] failed to prepare transaction at peer node + \x + SELECT + pflfailedloginattempts, +@@ -597,21 +597,13 @@ + pflpasswordminlen, + pflpasswordrequirecomplex + FROM pg_profile WHERE pflname = 'test_profile'; +--[ RECORD 1 ]-------------+--- +-pflfailedloginattempts | -2 +-pflfailedauthkeeptime | -2 +-pfluserinactivetime | -2 +-pflpasswordreusetime | -2 +-pflpasswordreusemax | -2 +-pflpasswordlifetime | -2 +-pflpasswordgracetime | -2 +-pflpasswordminuniqchars | -2 +-pflpasswordminlen | -2 +-pflpasswordrequirecomplex | -2 ++(0 rows) + + \x + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + CREATE PROFILE test_profile; ++ERROR: [MTM] failed to prepare transaction at peer node + ALTER PROFILE test_profile LIMIT + FAILED_LOGIN_ATTEMPTS DEFAULT + FAILED_AUTH_KEEP_TIME DEFAULT +@@ -623,6 +615,7 @@ + PASSWORD_MIN_UNIQUE_CHARS DEFAULT + PASSWORD_MIN_LEN DEFAULT + PASSWORD_REQUIRE_COMPLEX DEFAULT; ++ERROR: profile "test_profile" does not exist + \x + SELECT + pflfailedloginattempts, +@@ -636,20 +629,11 @@ + pflpasswordminlen, + pflpasswordrequirecomplex + FROM pg_profile WHERE pflname = 'test_profile'; +--[ RECORD 1 ]-------------+--- +-pflfailedloginattempts | -2 +-pflfailedauthkeeptime | -2 +-pfluserinactivetime | -2 +-pflpasswordreusetime | -2 +-pflpasswordreusemax | -2 +-pflpasswordlifetime | -2 +-pflpasswordgracetime | -2 +-pflpasswordminuniqchars | -2 +-pflpasswordminlen | -2 +-pflpasswordrequirecomplex | -2 ++(0 rows) + + \x + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + -- Check that almost all profile options (except for PASSWORD_REQUIRE_COMPLEX) + -- support the value UNLIMITED. + CREATE PROFILE test_profile LIMIT +@@ -662,6 +646,7 @@ + PASSWORD_GRACE_TIME UNLIMITED + PASSWORD_MIN_UNIQUE_CHARS UNLIMITED + PASSWORD_MIN_LEN UNLIMITED; ++ERROR: [MTM] failed to prepare transaction at peer node + \x + SELECT + pflfailedloginattempts, +@@ -675,21 +660,13 @@ + pflpasswordminlen, + pflpasswordrequirecomplex + FROM pg_profile WHERE pflname = 'test_profile'; +--[ RECORD 1 ]-------------+--- +-pflfailedloginattempts | -1 +-pflfailedauthkeeptime | -1 +-pfluserinactivetime | -1 +-pflpasswordreusetime | -1 +-pflpasswordreusemax | -1 +-pflpasswordlifetime | -1 +-pflpasswordgracetime | -1 +-pflpasswordminuniqchars | -1 +-pflpasswordminlen | -1 +-pflpasswordrequirecomplex | -2 ++(0 rows) + + \x + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist + CREATE PROFILE test_profile; ++ERROR: [MTM] failed to prepare transaction at peer node + ALTER PROFILE test_profile LIMIT + FAILED_LOGIN_ATTEMPTS UNLIMITED + FAILED_AUTH_KEEP_TIME UNLIMITED +@@ -700,6 +677,7 @@ + PASSWORD_GRACE_TIME UNLIMITED + PASSWORD_MIN_UNIQUE_CHARS UNLIMITED + PASSWORD_MIN_LEN UNLIMITED; ++ERROR: profile "test_profile" does not exist + \x + SELECT + pflfailedloginattempts, +@@ -713,17 +691,8 @@ + pflpasswordminlen, + pflpasswordrequirecomplex + FROM pg_profile WHERE pflname = 'test_profile'; +--[ RECORD 1 ]-------------+--- +-pflfailedloginattempts | -1 +-pflfailedauthkeeptime | -1 +-pfluserinactivetime | -1 +-pflpasswordreusetime | -1 +-pflpasswordreusemax | -1 +-pflpasswordlifetime | -1 +-pflpasswordgracetime | -1 +-pflpasswordminuniqchars | -1 +-pflpasswordminlen | -1 +-pflpasswordrequirecomplex | -2 ++(0 rows) + + \x + DROP PROFILE test_profile; ++ERROR: profile "test_profile" does not exist diff ../../../src/test/regress/expected/sanity_check.out ../tmp_check/regress_outdir/results/sanity_check.out --- ../../../src/test/regress/expected/sanity_check.out CENSORED +++ ../tmp_check/regress_outdir/results/sanity_check.out CENSORED @@ -297,7 +992,7 @@ diff ../../../src/test/regress/expected/sanity_check.out ../tmp_check/regress_ou num_data|f num_exp_add|t num_exp_div|t -@@ -140,7 +146,6 @@ +@@ -141,7 +147,6 @@ pg_policy|t pg_proc|t pg_profile|t @@ -305,7 +1000,7 @@ diff ../../../src/test/regress/expected/sanity_check.out ../tmp_check/regress_ou pg_publication_rel|t pg_range|t pg_replication_origin|t -@@ -154,7 +159,6 @@ +@@ -155,7 +160,6 @@ pg_statistic|t pg_statistic_ext|t pg_statistic_ext_data|t @@ -313,7 +1008,7 @@ diff ../../../src/test/regress/expected/sanity_check.out ../tmp_check/regress_ou pg_subscription_rel|t pg_tablespace|t pg_transform|t -@@ -185,6 +189,7 @@ +@@ -187,6 +191,7 @@ sql_sizing|f stud_emp|f student|f @@ -321,6 +1016,473 @@ diff ../../../src/test/regress/expected/sanity_check.out ../tmp_check/regress_ou tab_core_types|f tableam_parted_a_heap2|f tableam_parted_b_heap2|f +diff ../../../src/test/regress/expected/select_into.out ../tmp_check/regress_outdir/results/select_into.out +--- ../../../src/test/regress/expected/select_into.out CENSORED ++++ ../tmp_check/regress_outdir/results/select_into.out CENSORED +@@ -50,27 +50,19 @@ + PREPARE data_sel AS SELECT generate_series(1,3); + CREATE TABLE selinto_schema.tbl_withdata3 (a) AS + EXECUTE data_sel WITH DATA; ++ERROR: [MTM] failed to prepare transaction at peer node + EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE selinto_schema.tbl_withdata4 (a) AS + EXECUTE data_sel WITH DATA; +- QUERY PLAN +--------------------------------------- +- ProjectSet (actual rows=3 loops=1) +- -> Result (actual rows=1 loops=1) +-(2 rows) +- ++ERROR: [MTM] failed to prepare transaction at peer node + -- EXECUTE and WITH NO DATA, passes. + CREATE TABLE selinto_schema.tbl_nodata3 (a) AS + EXECUTE data_sel WITH NO DATA; ++ERROR: [MTM] failed to prepare transaction at peer node + EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE selinto_schema.tbl_nodata4 (a) AS + EXECUTE data_sel WITH NO DATA; +- QUERY PLAN +-------------------------------- +- ProjectSet (never executed) +- -> Result (never executed) +-(2 rows) +- ++ERROR: [MTM] failed to prepare transaction at peer node + RESET SESSION AUTHORIZATION; + ALTER DEFAULT PRIVILEGES FOR ROLE regress_selinto_user + GRANT INSERT ON TABLES TO regress_selinto_user; +@@ -78,15 +70,11 @@ + RESET SESSION AUTHORIZATION; + DEALLOCATE data_sel; + DROP SCHEMA selinto_schema CASCADE; +-NOTICE: drop cascades to 8 other objects ++NOTICE: drop cascades to 4 other objects + DETAIL: drop cascades to table selinto_schema.tbl_withdata1 + drop cascades to table selinto_schema.tbl_withdata2 + drop cascades to table selinto_schema.tbl_nodata1 + drop cascades to table selinto_schema.tbl_nodata2 +-drop cascades to table selinto_schema.tbl_withdata3 +-drop cascades to table selinto_schema.tbl_withdata4 +-drop cascades to table selinto_schema.tbl_nodata3 +-drop cascades to table selinto_schema.tbl_nodata4 + DROP USER regress_selinto_user; + -- Tests for WITH NO DATA and column name consistency + CREATE TABLE ctas_base (i int, j int); +diff ../../../src/test/regress/expected/join.out ../tmp_check/regress_outdir/results/join.out +--- ../../../src/test/regress/expected/join.out CENSORED ++++ ../tmp_check/regress_outdir/results/join.out CENSORED +@@ -4936,11 +4936,14 @@ + -- Trivial self-join case. + explain (costs off) + select p.* from sj p, sj q where q.a = p.a and q.b = q.a - 1; +- QUERY PLAN +------------------------------------------------ +- Seq Scan on sj q +- Filter: ((a IS NOT NULL) AND (b = (a - 1))) +-(2 rows) ++ QUERY PLAN ++------------------------------- ++ Nested Loop ++ Join Filter: (p.a = q.a) ++ -> Seq Scan on sj q ++ Filter: (b = (a - 1)) ++ -> Seq Scan on sj p ++(5 rows) + + select p.* from sj p, sj q where q.a = p.a and q.b = q.a - 1; + a | b | c +@@ -4954,11 +4957,15 @@ + select * from sj p + where exists (select * from sj q + where q.a = p.a and q.b < 10); +- QUERY PLAN +------------------------------------------- +- Seq Scan on sj q +- Filter: ((a IS NOT NULL) AND (b < 10)) +-(2 rows) ++ QUERY PLAN ++-------------------------------- ++ Nested Loop ++ Join Filter: (p.a = q.a) ++ -> Seq Scan on sj p ++ -> Materialize ++ -> Seq Scan on sj q ++ Filter: (b < 10) ++(6 rows) + + select * from sj p where exists (select * from sj q where q.a = p.a and q.b < 10); + a | b | c +@@ -4985,13 +4992,11 @@ + (select a as x from sj where false) as q1, + (select a as y from sj where false) as q2 + where q1.x = q2.y; +- QUERY PLAN +---------------------------------- ++ QUERY PLAN ++-------------------------- + Result + One-Time Filter: false +- -> Seq Scan on sj +- Filter: (a IS NOT NULL) +-(4 rows) ++(2 rows) + + -- We can't use a cross-EC generated self join qual because of current logic of + -- the generate_join_implied_equalities routine. +@@ -5032,11 +5037,18 @@ + explain (costs off) + select * from sj t1 join sj t2 on t1.a = t2.a and t1.b = t2.b + join sj t3 on t2.a = t3.a and t2.b + 1 = t3.b + 1; +- QUERY PLAN +---------------------------------------------------------------------------- +- Seq Scan on sj t3 +- Filter: ((a IS NOT NULL) AND (b IS NOT NULL) AND ((b + 1) IS NOT NULL)) +-(2 rows) ++ QUERY PLAN ++-------------------------------------------------------------------------------- ++ Nested Loop ++ Join Filter: ((t1.a = t2.a) AND (t1.b = t2.b) AND ((t3.b + 1) = (t2.b + 1))) ++ -> Seq Scan on sj t2 ++ -> Materialize ++ -> Nested Loop ++ Join Filter: (t1.a = t3.a) ++ -> Seq Scan on sj t1 ++ -> Materialize ++ -> Seq Scan on sj t3 ++(9 rows) + + -- subselect that references the removed relation + explain (costs off) +@@ -5045,14 +5057,17 @@ + where t1.a = t2.a; + QUERY PLAN + ------------------------------------------ +- Seq Scan on sj t2 +- Filter: (a IS NOT NULL) ++ Nested Loop ++ Join Filter: (t1.a = t2.a) ++ -> Seq Scan on sj t1 ++ -> Materialize ++ -> Seq Scan on sj t2 + SubPlan 1 + -> Result +- One-Time Filter: (t2.a = t2.a) ++ One-Time Filter: (t2.a = t1.a) + -> Seq Scan on sj +- Filter: (a = t2.a) +-(7 rows) ++ Filter: (a = t1.a) ++(10 rows) + + -- self-join under outer join + explain (costs off) +@@ -5061,12 +5076,15 @@ + QUERY PLAN + ------------------------------------ + Nested Loop Left Join +- Join Filter: (y.a = z.q1) +- -> Seq Scan on sj y +- Filter: (a IS NOT NULL) ++ Join Filter: (x.a = z.q1) ++ -> Nested Loop ++ Join Filter: (x.a = y.a) ++ -> Seq Scan on sj x ++ -> Materialize ++ -> Seq Scan on sj y + -> Materialize + -> Seq Scan on int8_tbl z +-(6 rows) ++(9 rows) + + explain (costs off) + select * from sj x join sj y on x.a = y.a +@@ -5075,11 +5093,14 @@ + ------------------------------------ + Nested Loop Left Join + Join Filter: (y.a = z.q1) +- -> Seq Scan on sj y +- Filter: (a IS NOT NULL) ++ -> Nested Loop ++ Join Filter: (x.a = y.a) ++ -> Seq Scan on sj x ++ -> Materialize ++ -> Seq Scan on sj y + -> Materialize + -> Seq Scan on int8_tbl z +-(6 rows) ++(9 rows) + + -- Test that placeholders are updated correctly after join removal + explain (costs off) +@@ -5088,44 +5109,56 @@ + right join sj j1 inner join sj j2 on j1.a = j2.a + on true) z + on true; +- QUERY PLAN +------------------------------------------- ++ QUERY PLAN ++------------------------------------------- + Nested Loop Left Join + -> Result + -> Nested Loop Left Join +- -> Seq Scan on sj j2 +- Filter: (a IS NOT NULL) ++ -> Nested Loop ++ Join Filter: (j1.a = j2.a) ++ -> Seq Scan on sj j1 ++ -> Materialize ++ -> Seq Scan on sj j2 + -> Materialize + -> Seq Scan on int8_tbl y +-(7 rows) ++(10 rows) + + -- Test that OR predicated are updated correctly after join removal + CREATE TABLE tab_with_flag ( id INT PRIMARY KEY, is_flag SMALLINT); + CREATE INDEX idx_test_is_flag ON tab_with_flag (is_flag); + explain (costs off) + SELECT COUNT(*) FROM tab_with_flag WHERE (is_flag IS NULL OR is_flag = 0) AND id IN (SELECT id FROM tab_with_flag WHERE id IN (2, 3)); +- QUERY PLAN +----------------------------------------------------------------------------------- ++ QUERY PLAN ++------------------------------------------------------------------------ + Aggregate +- -> Bitmap Heap Scan on tab_with_flag +- Recheck Cond: ((id = ANY ('{2,3}'::integer[])) AND (id IS NOT NULL)) +- Filter: ((is_flag IS NULL) OR (is_flag = 0)) +- -> Bitmap Index Scan on tab_with_flag_pkey +- Index Cond: ((id = ANY ('{2,3}'::integer[])) AND (id IS NOT NULL)) +-(6 rows) ++ -> Nested Loop ++ -> Bitmap Heap Scan on tab_with_flag tab_with_flag_1 ++ Recheck Cond: (id = ANY ('{2,3}'::integer[])) ++ -> Bitmap Index Scan on tab_with_flag_pkey ++ Index Cond: (id = ANY ('{2,3}'::integer[])) ++ -> Memoize ++ Cache Key: tab_with_flag_1.id ++ Cache Mode: logical ++ -> Index Scan using tab_with_flag_pkey on tab_with_flag ++ Index Cond: (id = tab_with_flag_1.id) ++ Filter: ((is_flag IS NULL) OR (is_flag = 0)) ++(12 rows) + + DROP TABLE tab_with_flag; + -- HAVING clause + explain (costs off) + select p.b from sj p join sj q on p.a = q.a group by p.b having sum(p.a) = 1; +- QUERY PLAN +---------------------------------- ++ QUERY PLAN ++------------------------------------ + HashAggregate +- Group Key: q.b +- Filter: (sum(q.a) = 1) +- -> Seq Scan on sj q +- Filter: (a IS NOT NULL) +-(5 rows) ++ Group Key: p.b ++ Filter: (sum(p.a) = 1) ++ -> Nested Loop ++ Join Filter: (p.a = q.a) ++ -> Seq Scan on sj p ++ -> Materialize ++ -> Seq Scan on sj q ++(8 rows) + + -- update lateral references and range table entry reference + explain (verbose, costs off) +@@ -5135,13 +5168,20 @@ + ------------------------------------------------------ + Nested Loop + Output: 1 +- -> Seq Scan on public.sj y +- Output: y.a, y.b, y.c +- Filter: (y.a IS NOT NULL) ++ -> Nested Loop ++ Output: x.a ++ Inner Unique: true ++ Join Filter: (x.a = y.a) ++ -> Seq Scan on public.sj x ++ Output: x.a, x.b, x.c ++ -> Materialize ++ Output: y.a ++ -> Seq Scan on public.sj y ++ Output: y.a + -> Function Scan on pg_catalog.generate_series gs + Output: gs.i +- Function Call: generate_series(1, y.a) +-(8 rows) ++ Function Call: generate_series(1, x.a) ++(15 rows) + + explain (verbose, costs off) + select 1 from (select y.* from sj x, sj y where x.a = y.a) q, +@@ -5150,13 +5190,20 @@ + ------------------------------------------------------ + Nested Loop + Output: 1 +- -> Seq Scan on public.sj y +- Output: y.a, y.b, y.c +- Filter: (y.a IS NOT NULL) ++ -> Nested Loop ++ Output: y.a ++ Inner Unique: true ++ Join Filter: (x.a = y.a) ++ -> Seq Scan on public.sj x ++ Output: x.a, x.b, x.c ++ -> Materialize ++ Output: y.a ++ -> Seq Scan on public.sj y ++ Output: y.a + -> Function Scan on pg_catalog.generate_series gs + Output: gs.i + Function Call: generate_series(1, y.a) +-(8 rows) ++(15 rows) + + -- Test that a non-EC-derived join clause is processed correctly. Use an + -- outer join so that we can't form an EC. +@@ -5165,22 +5212,29 @@ + QUERY PLAN + ------------------------------------ + Nested Loop Left Join +- Join Filter: ((q.a + q.a) = r.a) +- -> Seq Scan on sj q +- Filter: (a IS NOT NULL) ++ Join Filter: ((p.a + q.a) = r.a) ++ -> Nested Loop ++ Join Filter: (p.a = q.a) ++ -> Seq Scan on sj p ++ -> Materialize ++ -> Seq Scan on sj q + -> Materialize + -> Seq Scan on sj r +-(6 rows) ++(9 rows) + + -- FIXME this constant false filter doesn't look good. Should we merge + -- equivalence classes? + explain (costs off) + select * from sj p, sj q where p.a = q.a and p.b = 1 and q.b = 2; +- QUERY PLAN +------------------------------------------------------ +- Seq Scan on sj q +- Filter: ((a IS NOT NULL) AND (b = 2) AND (b = 1)) +-(2 rows) ++ QUERY PLAN ++---------------------------- ++ Nested Loop ++ Join Filter: (p.a = q.a) ++ -> Seq Scan on sj p ++ Filter: (b = 1) ++ -> Seq Scan on sj q ++ Filter: (b = 2) ++(6 rows) + + -- Check that attr_needed is updated correctly after self-join removal. In this + -- test, the join of j1 with j2 is removed. k1.b is required at either j1 or j2. +@@ -5195,24 +5249,29 @@ + explain (costs off) select 1 from + (sk k1 join sk k2 on k1.a = k2.a) + join (sj j1 join sj j2 on j1.a = j2.a) on j1.b = k1.b; +- QUERY PLAN +------------------------------------------------------ ++ QUERY PLAN ++----------------------------------------------------------------- + Nested Loop +- Join Filter: (k1.b = j2.b) ++ Join Filter: (k1.b = j1.b) + -> Nested Loop + -> Index Scan using sk_a_idx on sk k1 + -> Index Only Scan using sk_a_idx on sk k2 + Index Cond: (a = k1.a) + -> Materialize +- -> Index Scan using sj_a_key on sj j2 +- Index Cond: (a IS NOT NULL) +-(9 rows) ++ -> Nested Loop ++ -> Index Scan using sj_a_key on sj j1 ++ -> Memoize ++ Cache Key: j1.a ++ Cache Mode: logical ++ -> Index Only Scan using sj_a_key on sj j2 ++ Index Cond: (a = j1.a) ++(14 rows) + + explain (costs off) select 1 from + (sk k1 join sk k2 on k1.a = k2.a) + join (sj j1 join sj j2 on j1.a = j2.a) on j2.b = k1.b; +- QUERY PLAN +------------------------------------------------------ ++ QUERY PLAN ++------------------------------------------------------------ + Nested Loop + Join Filter: (k1.b = j2.b) + -> Nested Loop +@@ -5220,9 +5279,14 @@ + -> Index Only Scan using sk_a_idx on sk k2 + Index Cond: (a = k1.a) + -> Materialize +- -> Index Scan using sj_a_key on sj j2 +- Index Cond: (a IS NOT NULL) +-(9 rows) ++ -> Nested Loop ++ -> Index Only Scan using sj_a_key on sj j1 ++ -> Memoize ++ Cache Key: j1.a ++ Cache Mode: logical ++ -> Index Scan using sj_a_key on sj j2 ++ Index Cond: (a = j1.a) ++(14 rows) + + reset join_collapse_limit; + reset enable_seqscan; +@@ -5230,12 +5294,18 @@ + CREATE TABLE emp1 ( id SERIAL PRIMARY KEY NOT NULL, code int); + explain (verbose, costs off) + SELECT * FROM emp1 e1, emp1 e2 WHERE e1.id = e2.id AND e2.code <> e1.code; +- QUERY PLAN +----------------------------------------------------------- +- Seq Scan on public.emp1 e2 +- Output: e2.id, e2.code, e2.id, e2.code +- Filter: ((e2.id IS NOT NULL) AND (e2.code <> e2.code)) +-(3 rows) ++ QUERY PLAN ++---------------------------------------------------- ++ Nested Loop ++ Output: e1.id, e1.code, e2.id, e2.code ++ Inner Unique: true ++ -> Seq Scan on public.emp1 e1 ++ Output: e1.id, e1.code ++ -> Index Scan using emp1_pkey on public.emp1 e2 ++ Output: e2.id, e2.code ++ Index Cond: (e2.id = e1.id) ++ Filter: (e2.code <> e1.code) ++(9 rows) + + -- We can remove the join even if we find the join can't duplicate rows and + -- the base quals of each side are different. In the following case we end up +@@ -5246,11 +5316,15 @@ + -- Both sides are unique, but base quals are different + explain (costs off) + select * from sl t1, sl t2 where t1.a = t2.a and t1.b = 1 and t2.b = 2; +- QUERY PLAN +------------------------------------------------------ +- Seq Scan on sl t2 +- Filter: ((a IS NOT NULL) AND (b = 2) AND (b = 1)) +-(2 rows) ++ QUERY PLAN ++------------------------------ ++ Nested Loop ++ Join Filter: (t1.a = t2.a) ++ -> Seq Scan on sl t1 ++ Filter: (b = 1) ++ -> Seq Scan on sl t2 ++ Filter: (b = 2) ++(6 rows) + + -- + ---- Only one side is unqiue diff ../../../src/test/regress/expected/transactions.out ../tmp_check/regress_outdir/results/transactions.out --- ../../../src/test/regress/expected/transactions.out CENSORED +++ ../tmp_check/regress_outdir/results/transactions.out CENSORED @@ -470,8 +1632,8 @@ diff ../../../src/test/regress/expected/transactions.out ../tmp_check/regress_ou COMMIT; START TRANSACTION ISOLATION LEVEL REPEATABLE READ\; INSERT INTO abc VALUES (16)\; ROLLBACK AND CHAIN; -- 16 ok SHOW transaction_isolation; -- transaction is active at this point -@@ -1028,7 +999,7 @@ - ROLLBACK; +@@ -1029,7 +1000,7 @@ + SET default_transaction_isolation = 'read committed'; -- START TRANSACTION + COMMIT/ROLLBACK + COMMIT/ROLLBACK AND CHAIN START TRANSACTION ISOLATION LEVEL REPEATABLE READ\; INSERT INTO abc VALUES (17)\; COMMIT\; INSERT INTO abc VALUES (18)\; COMMIT AND CHAIN; -- 17 commit, 18 error -ERROR: COMMIT AND CHAIN can only be used in transaction blocks @@ -479,7 +1641,7 @@ diff ../../../src/test/regress/expected/transactions.out ../tmp_check/regress_ou SHOW transaction_isolation; -- out of transaction block transaction_isolation ----------------------- -@@ -1047,9 +1018,8 @@ +@@ -1049,9 +1020,8 @@ a ---- 7 @@ -567,48 +1729,431 @@ diff ../../../src/test/regress/expected/rowsecurity.out ../tmp_check/regress_out SELECT * FROM pg_policies WHERE schemaname = 'regress_rls_schema' AND tablename like '%part_document%' ORDER BY policyname; schemaname | tablename | policyname | permissive | roles | cmd | qual | with_check --------------------+---------------+------------+-------------+--------------------+-----+--------------------------------------------+------------ -diff ../../../src/test/regress/expected/atx.out ../tmp_check/regress_outdir/results/atx.out ---- ../../../src/test/regress/expected/atx.out CENSORED -+++ ../tmp_check/regress_outdir/results/atx.out CENSORED -@@ -851,6 +851,7 @@ - declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); - insert into atx_tt1 values(2); - commit; -+ERROR: cannot PREPARE a transaction that has created a cursor WITH HOLD - commit; - begin; - begin autonomous; -@@ -866,6 +867,7 @@ - drop function count_tt1_s(); - drop table if exists atx_tt1; - close c2; -+ERROR: cursor "c2" does not exist - -- 13 - create table atx_13_t(i int); - begin; -@@ -985,9 +987,7 @@ - insert into atx_tt2 values(1); - declare c2 cursor with hold for select error_function(); - commit; +diff ../../../src/test/regress/expected/object_address.out ../tmp_check/regress_outdir/results/object_address.out +--- ../../../src/test/regress/expected/object_address.out CENSORED ++++ ../tmp_check/regress_outdir/results/object_address.out CENSORED +@@ -580,44 +580,6 @@ + AS descr + FROM objects + ORDER BY objects.classid, objects.objid, objects.objsubid; +-("(""default acl"",,,)")|("(""default acl"",,)")|NULL +-("(tablespace,,,)")|("(tablespace,,)")|NULL +-("(type,,,)")|("(type,,)")|NULL +-("(routine,,,)")|("(routine,,)")|NULL +-("(relation,,,)")|("(relation,,)")|NULL +-("(""table column"",,,)")|("(""table column"",,)")|NULL +-("(role,,,)")|("(role,,)")|NULL +-("(database,,,)")|("(database,,)")|NULL +-("(server,,,)")|("(server,,)")|NULL +-("(""user mapping"",,,)")|("(""user mapping"",,)")|NULL +-("(""foreign-data wrapper"",,,)")|("(""foreign-data wrapper"",,)")|NULL +-("(""access method"",,,)")|("(""access method"",,)")|NULL +-("(""operator of access method"",,,)")|("(""operator of access method"",,)")|NULL +-("(""function of access method"",,,)")|("(""function of access method"",,)")|NULL +-("(""default value"",,,)")|("(""default value"",,)")|NULL +-("(cast,,,)")|("(cast,,)")|NULL +-("(constraint,,,)")|("(constraint,,)")|NULL +-("(conversion,,,)")|("(conversion,,)")|NULL +-("(language,,,)")|("(language,,)")|NULL +-("(""large object"",,,)")|("(""large object"",,)")|NULL +-("(schema,,,)")|("(schema,,)")|NULL +-("(""operator class"",,,)")|("(""operator class"",,)")|NULL +-("(operator,,,)")|("(operator,,)")|NULL +-("(rule,,,)")|("(rule,,)")|NULL +-("(trigger,,,)")|("(trigger,,)")|NULL +-("(""operator family"",,,)")|("(""operator family"",,)")|NULL +-("(extension,,,)")|("(extension,,)")|NULL +-("(policy,,,)")|("(policy,,)")|NULL +-("(""statistics object"",,,)")|("(""statistics object"",,)")|NULL +-("(collation,,,)")|("(collation,,)")|NULL +-("(""event trigger"",,,)")|("(""event trigger"",,)")|NULL +-("(transform,,,)")|("(transform,,)")|NULL +-("(""text search dictionary"",,,)")|("(""text search dictionary"",,)")|NULL +-("(""text search parser"",,,)")|("(""text search parser"",,)")|NULL +-("(""text search configuration"",,,)")|("(""text search configuration"",,)")|NULL +-("(""text search template"",,,)")|("(""text search template"",,)")|NULL +-("(subscription,,,)")|("(subscription,,)")|NULL +-("(publication,,,)")|("(publication,,)")|NULL +-("(""publication relation"",,,)")|("(""publication relation"",,)")|NULL ++ERROR: unrecognized object class: 16512 + -- restore normal output mode + \a\t +diff ../../../src/test/regress/expected/atx2.out ../tmp_check/regress_outdir/results/atx2.out +--- ../../../src/test/regress/expected/atx2.out CENSORED ++++ ../tmp_check/regress_outdir/results/atx2.out CENSORED +@@ -287,362 +287,9 @@ + return 1; + end$$; + select atx_lo_test10(:my_loid); +- atx_lo_test10 +---------------- +- 1 +-(1 row) +- +-select lo_unlink(:my_loid); +- lo_unlink +------------ +- 1 +-(1 row) +- +--- put some initial data +-select lo_creat(-1) as my_loid \gset +-select lo_put( :my_loid, 0, 'lo test' ); +- lo_put +--------- +- +-(1 row) +- +--- This function should not fail +-select * from lo_test_func( :my_loid ); +- lo_test_func +--------------- +- 0 +-(1 row) +- +--- Read something +-select convert_from(data, 'UTF8') from pg_largeobject where loid = :my_loid; +- convert_from +------------------ +- My mega lo test +-(1 row) +- +--- 11 +-DO $body$ +-begin +- begin +- begin autonomous +- set datestyle = 'euro'; +- end; +- exception +- when others then +- raise notice 'exception %, %', SQLSTATE, SQLERRM; +- end; +-end; +-$body$ language plpgsql; +--- 12 +-create table if not exists atx_tt1(f1 int); +-create function count_tt1_v() returns int8 as 'select count(*) from atx_tt1' language sql volatile; +-create function count_tt1_s() returns int8 as 'select count(*) from atx_tt1' language sql stable; +-begin; +- begin autonomous; +- insert into atx_tt1 values(1); +- declare c1 cursor for select count_tt1_v(), count_tt1_s(); +- insert into atx_tt1 values(2); +- fetch all from c1; +- count_tt1_v | count_tt1_s +--------------+------------- +- 2 | 1 +-(1 row) +- +- rollback; +-rollback; +-begin; +- begin autonomous; +- insert into atx_tt1 values(1); +- declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); +- insert into atx_tt1 values(2); +- commit; +-commit; +-begin; +- begin autonomous; +- insert into atx_tt1 values(1); +- declare c1 cursor for select count_tt1_v(), count_tt1_s(); +- begin autonomous; +- fetch all from c1; +-ERROR: cursor "c1" does not exist +- rollback; +- rollback; +-rollback; +-drop function count_tt1_v(); +-drop function count_tt1_s(); +-drop table if exists atx_tt1; +-close c2; +--- 13 +-create table atx_13_t(i int); +-begin; +- begin autonomous; +- update atx_13_t set i = 1; +- rollback; +- begin autonomous; +- update atx_13_t set i = 2; +- rollback; +- drop table if exists atx_13_t; +- begin autonomous; +- update atx_13_t set i = 3 where i in (select i from atx_13_t); +-ERROR: lockmode RowExclusiveLock conflicts with lock AccessExclusiveLock of parent transaction, acquiring this lock in an autonomous transaction will lead to a sure deadlock +-LINE 1: update atx_13_t set i = 3 where i in (select i from atx_13_t... +- ^ +- rollback; +-commit; +--- 14 +-create or replace function atx_14_trigger_func() returns trigger as $body$ +-begin +- return null; +-end; +-$body$ language plpgsql; +-create table atx_14_test(a text, b text); +-create trigger atx_14_test_audit +-after insert on atx_14_test +-for each row execute procedure atx_14_trigger_func(); +-begin; +- insert into atx_14_test values (125); +- begin autonomous transaction; +- commit; +- insert into atx_14_test values (1); +-commit; +-drop table if exists atx_14_test; +-drop function atx_14_trigger_func(); +--- 15 +-create or replace function atx_15_dummy() returns text as $$ +-declare +- x text; +-begin +- x := 'one'; +- begin autonomous +- x := 'two'; +- end; +- return x; +-end; $$ language plpgsql; +-create table atx_15_test as select 1 as int, NULL as name; +-update atx_15_test set name = atx_15_dummy() returning *; +- int | name +------+------ +- 1 | two +-(1 row) +- +-drop table if exists atx_15_test; +-drop function if exists atx_15_dummy(); +--- 16 +-create table test(i int); +-begin; +- begin autonomous; +- insert into test values(1); +- declare c cursor for select * from test; +- begin autonomous; +- commit; +- rollback; +-rollback; +-drop table if exists test; +--- 17 +-create table test(f1 int); +-begin; +- begin autonomous; +- insert into test values(1); +- declare c1 cursor for select * from test; +- begin autonomous; +- fetch all from c1; +-ERROR: cursor "c1" does not exist +- rollback; +- rollback; +-rollback; +-drop table if exists test; +--- 19 +-create or replace function error_func() returns int as $body$ +-begin +- return 0/0; +-end; +-$body$ language plpgsql; +-DO $body$ +-begin +- begin +- begin autonomous +- select error_func(); +- end; +- exception +- when others then +- raise notice 'exception %, %', SQLSTATE, SQLERRM; +- end; +-end; +-$body$ language plpgsql; +-NOTICE: exception 22012, division by zero +-drop function if exists error_func(); +--- 21 +-CREATE OR REPLACE FUNCTION error_function() +- RETURNS integer AS +-$BODY$ +-begin +- begin autonomous +- SELECT 0/0; +- end; +- return 1; +-exception +- when others then +- raise notice 'other exception %, %', SQLSTATE, SQLERRM; +-end; +-$BODY$ LANGUAGE plpgsql; +-create table if not exists atx_tt2(f1 int); +-begin; +- begin autonomous; +- insert into atx_tt2 values(1); +- declare c2 cursor with hold for select error_function(); +- commit; -NOTICE: other exception 22012, division by zero -ERROR: control reached end of function without RETURN -CONTEXT: PL/pgSQL function error_function() -+ERROR: cannot PREPARE a transaction that has created a cursor WITH HOLD - commit; - drop function if exists error_function(); - drop table if exists atx_tt2; -@@ -1074,6 +1074,7 @@ - RESET client_min_messages; - create database regression_atx_test_database; - ALTER DATABASE "regression_atx_test_database" SET lc_messages TO 'C'; -+ERROR: [MTM] failed to prepare transaction at peer node - \c regression_atx_test_database - create table atx_test as select 1 as id; - begin; -diff ../../../src/test/regress/expected/atx5.out ../tmp_check/regress_outdir/results/atx5.out ---- ../../../src/test/regress/expected/atx5.out CENSORED -+++ ../tmp_check/regress_outdir/results/atx5.out CENSORED -@@ -24,10 +24,7 @@ +-commit; +-drop function if exists error_function(); +-drop table if exists atx_tt2; +--- 22 +-create or replace function if_modified_func_22() returns trigger as $body$ +-declare +- v_new_data text; +-begin +- v_new_data := row(new.*); +- begin autonomous +- return new; +- end; +-end; +-$body$ language plpgsql; +-create table atx_test_22(a text, b text); +-create trigger atx_test_22_audit +-after insert on atx_test_22 +-for each row execute procedure if_modified_func_22(); +-begin; +- insert into atx_test_22 values (1); +- begin autonomous transaction; +- commit; +- insert into atx_test_22 values (2); +-commit; +-drop table if exists atx_test_22; +-drop function if exists if_modified_func_22(); +--- 23 +-CREATE OR REPLACE FUNCTION error_function3() +- RETURNS integer AS +-$BODY$ +-begin +- begin autonomous +- SELECT 0/0; +- end; +- return 1; +-exception +- when others then +- raise notice 'other exception %, %', SQLSTATE, SQLERRM; +-end; +-$BODY$ LANGUAGE plpgsql; +-begin; +- begin autonomous; +- declare c2 cursor with hold for select error_function3(); +- commit; +-NOTICE: other exception 22012, division by zero +-ERROR: control reached end of function without RETURN +-CONTEXT: PL/pgSQL function error_function3() +-commit; +-drop function if exists error_function3(); +-close c2; +-ERROR: cursor "c2" does not exist +--- 24 +-CREATE OR REPLACE FUNCTION error_function3() +- RETURNS integer AS +-$BODY$ +-begin +- begin autonomous +- SELECT 0/0; +- end; +- return 1; +-exception +- when others then +- raise notice 'other exception %, %', SQLSTATE, SQLERRM; +- return 0; +-end; +-$BODY$ LANGUAGE plpgsql; +-begin; +- begin autonomous; +- declare c3 cursor with hold for select error_function3(); +- commit; +-NOTICE: other exception 22012, division by zero +-commit; +-drop function if exists error_function3(); +-close c3; +--- 25 +-select count(*) * 0 as dummy_res from ( select pg_terminate_backend(pid) from pg_stat_activity where datname = 'regression_atx_test_database' ) as foo; +- dummy_res +------------ +- 0 +-(1 row) +- +-SET client_min_messages TO 'warning'; +-drop database if exists regression_atx_test_database; +-RESET client_min_messages; +-create database regression_atx_test_database; +-ALTER DATABASE "regression_atx_test_database" SET lc_messages TO 'C'; +-\c regression_atx_test_database +-create table atx_test as select 1 as id; +-begin; +- begin autonomous; +- create table tmp1 as select id from atx_test; +- delete from atx_test where id in ( select id from unknown ); +-ERROR: relation "unknown" does not exist +-LINE 1: delete from atx_test where id in ( select id from unknown ); +- ^ +- rollback; +- begin autonomous; +- drop table atx_test; +-\c regression +--- PGPRO-5052 +-BEGIN TRANSACTION; BEGIN AUTONOMOUS TRANSACTION; +-CREATE FUNCTION atx_srf_test_func() RETURNS setof text AS +-$$ SELECT 'foo'::varchar $$ +-LANGUAGE SQL; +-SELECT atx_srf_test_func(); +- atx_srf_test_func +-------------------- +- foo +-(1 row) +- +-COMMIT AUTONOMOUS; COMMIT; +-DROP FUNCTION atx_srf_test_func(); +--- PGPRO-5860 +-create table mmm5860(i int); +-create or replace function crash_func5860() returns int language plpgsql as $$ +-declare +-begin +- create table if not exists mmm5860(i int); +- begin autonomous +- begin +- create table if not exists mmm5860(i int); +- exception +- when others then +- raise notice 'other exception %, %', SQLSTATE, SQLERRM; +- end; +- end; +- return 1; +-end$$; +-select * from crash_func5860(); +-NOTICE: relation "mmm5860" already exists, skipping +-NOTICE: relation "mmm5860" already exists, skipping +- crash_func5860 +----------------- +- 1 +-(1 row) +- +-drop function crash_func5860(); +-drop table mmm5860; +--- PGPRO-6207 +-BEGIN; +-COMMIT AUTONOMOUS; +-WARNING: there is no autonomous transaction in progress +-BEGIN; +-ABORT AUTONOMOUS; +-WARNING: there is no autonomous transaction in progress +-BEGIN; +- SAVEPOINT sp; +-COMMIT AUTONOMOUS; +-WARNING: there is no autonomous transaction in progress +-BEGIN; +- SAVEPOINT sp; +-ABORT AUTONOMOUS; +-WARNING: there is no autonomous transaction in progress ++FATAL: RollbackAndReleaseCurrentSubTransaction: unexpected state DEFAULT ++CONTEXT: PL/pgSQL function atx_lo_test10(oid) line 9 during exception cleanup ++server closed the connection unexpectedly ++ This probably means the server terminated abnormally ++ before or while processing the request. ++connection to server was lost +diff ../../../src/test/regress/expected/atx3.out ../tmp_check/regress_outdir/results/atx3.out +--- ../../../src/test/regress/expected/atx3.out CENSORED ++++ ../tmp_check/regress_outdir/results/atx3.out CENSORED +@@ -115,10 +115,7 @@ NOTICE: function atx_test_30_one() does not exist, skipping NOTICE: function atx_test_30_one() does not exist, skipping NOTICE: function atx_test_30_one() does not exist, skipping @@ -620,10 +2165,7 @@ diff ../../../src/test/regress/expected/atx5.out ../tmp_check/regress_outdir/res SET client_min_messages = 'warning'; DROP FUNCTION IF EXISTS atx_test_30_one(); DROP FUNCTION IF EXISTS atx_test_30_two(); -diff ../../../src/test/regress/expected/atx9.out ../tmp_check/regress_outdir/results/atx9.out ---- ../../../src/test/regress/expected/atx9.out CENSORED -+++ ../tmp_check/regress_outdir/results/atx9.out CENSORED -@@ -29,50 +29,38 @@ +@@ -383,50 +380,38 @@ INSERT INTO abc VALUES (1); INSERT INTO abc VALUES (2); COMMIT AND CHAIN; -- TBLOCK_END @@ -683,7 +2225,7 @@ diff ../../../src/test/regress/expected/atx9.out ../tmp_check/regress_outdir/res COMMIT; ROLLBACK; BEGIN; -@@ -144,24 +132,13 @@ +@@ -498,24 +483,13 @@ SAVEPOINT x; COMMIT AND CHAIN; -- TBLOCK_SUBCOMMIT @@ -712,7 +2254,7 @@ diff ../../../src/test/regress/expected/atx9.out ../tmp_check/regress_outdir/res COMMIT; ROLLBACK; -- different mix of options just for fun -@@ -232,17 +209,14 @@ +@@ -586,17 +560,14 @@ COMMIT; -- not allowed outside a transaction block COMMIT AUTONOMOUS AND CHAIN; -- error @@ -732,6 +2274,18 @@ diff ../../../src/test/regress/expected/atx9.out ../tmp_check/regress_outdir/res RESET default_transaction_read_only; DROP TABLE abc; +diff ../../../src/test/regress/expected/sysviews.out ../tmp_check/regress_outdir/results/sysviews.out +--- ../../../src/test/regress/expected/sysviews.out CENSORED ++++ ../tmp_check/regress_outdir/results/sysviews.out CENSORED +@@ -119,7 +119,7 @@ + enable_partition_pruning | on + enable_partitionwise_aggregate | off + enable_partitionwise_join | off +- enable_self_join_removal | on ++ enable_self_join_removal | off + enable_seqscan | on + enable_sort | on + enable_tidscan | on diff ../../../src/test/regress/expected/rules.out ../tmp_check/regress_outdir/results/rules.out --- ../../../src/test/regress/expected/rules.out CENSORED +++ ../tmp_check/regress_outdir/results/rules.out CENSORED @@ -751,10 +2305,10 @@ diff ../../../src/test/regress/expected/rules.out ../tmp_check/regress_outdir/re iexit| SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit -@@ -1452,19 +1461,30 @@ - p.parameter_types, - p.from_sql - FROM pg_prepared_statement() p(name, statement, prepare_time, parameter_types, from_sql); +@@ -1443,19 +1452,30 @@ + p.generic_plans, + p.custom_plans + FROM pg_prepared_statement() p(name, statement, prepare_time, parameter_types, from_sql, generic_plans, custom_plans); -pg_prepared_xacts| SELECT p.transaction, - p.gid, - p.prepared, @@ -792,7 +2346,7 @@ diff ../../../src/test/regress/expected/rules.out ../tmp_check/regress_outdir/re LATERAL pg_get_publication_tables((p.pubname)::text) gpt(relid), (pg_class c JOIN pg_namespace n ON ((n.oid = c.relnamespace))) -@@ -1659,7 +1679,7 @@ +@@ -1651,7 +1671,7 @@ l.provider, l.label FROM (pg_seclabel l @@ -801,7 +2355,7 @@ diff ../../../src/test/regress/expected/rules.out ../tmp_check/regress_outdir/re WHERE (l.objsubid = 0) UNION ALL SELECT l.objoid, -@@ -1671,7 +1691,7 @@ +@@ -1663,7 +1683,7 @@ l.provider, l.label FROM (pg_shseclabel l @@ -810,7 +2364,7 @@ diff ../../../src/test/regress/expected/rules.out ../tmp_check/regress_outdir/re UNION ALL SELECT l.objoid, l.classoid, -@@ -2066,7 +2086,7 @@ +@@ -2099,7 +2119,7 @@ st.last_msg_receipt_time, st.latest_end_lsn, st.latest_end_time @@ -819,15 +2373,17 @@ diff ../../../src/test/regress/expected/rules.out ../tmp_check/regress_outdir/re LEFT JOIN pg_stat_get_subscription(NULL::oid) st(subid, relid, pid, received_lsn, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time) ON ((st.subid = su.oid))); pg_stat_sys_indexes| SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, -@@ -2408,6 +2428,17 @@ - FROM (unnest(s.stxkeys) k(k) - JOIN pg_attribute a ON (((a.attrelid = s.stxrelid) AND (a.attnum = k.k)))) - WHERE (NOT has_column_privilege(c.oid, a.attnum, 'select'::text))))) AND ((c.relrowsecurity = false) OR (NOT row_security_active(c.oid)))); +@@ -2524,6 +2544,19 @@ + LEFT JOIN pg_namespace sn ON ((sn.oid = s.stxnamespace))) + JOIN LATERAL ( SELECT unnest(pg_get_statisticsobjdef_expressions(s.oid)) AS expr, + unnest(sd.stxdexpr) AS a) stat ON ((stat.expr IS NOT NULL))); +pg_subscription| SELECT _pg_subscription.oid, + _pg_subscription.subdbid, + _pg_subscription.subname, + _pg_subscription.subowner, + _pg_subscription.subenabled, ++ _pg_subscription.subbinary, ++ _pg_subscription.substream, + _pg_subscription.subconninfo, + _pg_subscription.subslotname, + _pg_subscription.subsynccommit, @@ -837,6 +2393,50 @@ diff ../../../src/test/regress/expected/rules.out ../tmp_check/regress_outdir/re pg_tables| SELECT n.nspname AS schemaname, c.relname AS tablename, pg_get_userbyid(c.relowner) AS tableowner, +diff ../../../src/test/regress/expected/psql.out ../tmp_check/regress_outdir/results/psql.out +--- ../../../src/test/regress/expected/psql.out CENSORED ++++ ../tmp_check/regress_outdir/results/psql.out CENSORED +@@ -2813,36 +2813,14 @@ + CREATE VIEW view_heap_psql AS SELECT f1 from tbl_heap_psql; + CREATE MATERIALIZED VIEW mat_view_heap_psql USING heap_psql AS SELECT f1 from tbl_heap_psql; + \d+ tbl_heap_psql +- Table "tableam_display.tbl_heap_psql" +- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------+----------------+-----------+----------+---------+----------+--------------+------------- +- f1 | integer | | | | plain | | +- f2 | character(100) | | | | extended | | +- ++ERROR: permission denied for view pg_publication + \d+ tbl_heap +- Table "tableam_display.tbl_heap" +- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------+----------------+-----------+----------+---------+----------+--------------+------------- +- f1 | integer | | | | plain | | +- f2 | character(100) | | | | extended | | +- ++ERROR: permission denied for view pg_publication + \set HIDE_TABLEAM off + \d+ tbl_heap_psql +- Table "tableam_display.tbl_heap_psql" +- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------+----------------+-----------+----------+---------+----------+--------------+------------- +- f1 | integer | | | | plain | | +- f2 | character(100) | | | | extended | | +-Access method: heap_psql +- ++ERROR: permission denied for view pg_publication + \d+ tbl_heap +- Table "tableam_display.tbl_heap" +- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +---------+----------------+-----------+----------+---------+----------+--------------+------------- +- f1 | integer | | | | plain | | +- f2 | character(100) | | | | extended | | +-Access method: heap +- ++ERROR: permission denied for view pg_publication + -- AM is displayed for tables, indexes and materialized views. + \d+ + List of relations diff ../../../src/test/regress/expected/publication.out ../tmp_check/regress_outdir/results/publication.out --- ../../../src/test/regress/expected/publication.out CENSORED +++ ../tmp_check/regress_outdir/results/publication.out CENSORED @@ -869,6 +2469,104 @@ diff ../../../src/test/regress/expected/subscription.out ../tmp_check/regress_ou (1 row) -- fail - name already exists +diff ../../../src/test/regress/expected/equivclass.out ../tmp_check/regress_outdir/results/equivclass.out +--- ../../../src/test/regress/expected/equivclass.out CENSORED ++++ ../tmp_check/regress_outdir/results/equivclass.out CENSORED +@@ -438,15 +438,17 @@ + explain (costs off) + select * from ec0 m join ec0 n on m.ff = n.ff + join ec1 p on m.ff + n.ff = p.f1; +- QUERY PLAN +----------------------------------------- ++ QUERY PLAN ++------------------------------------------------ + Nested Loop +- Join Filter: ((n.ff + n.ff) = p.f1) +- -> Seq Scan on ec1 p ++ Join Filter: ((m.ff + n.ff) = p.f1) ++ -> Nested Loop ++ -> Seq Scan on ec0 m ++ -> Index Scan using ec0_pkey on ec0 n ++ Index Cond: (ff = m.ff) + -> Materialize +- -> Seq Scan on ec0 n +- Filter: (ff IS NOT NULL) +-(6 rows) ++ -> Seq Scan on ec1 p ++(8 rows) + + explain (costs off) + select * from ec0 m join ec0 n on m.ff = n.ff +@@ -454,12 +456,14 @@ + QUERY PLAN + --------------------------------------------------------------- + Nested Loop +- Join Filter: ((p.f1)::bigint = ((n.ff + n.ff))::int8alias1) +- -> Seq Scan on ec1 p ++ Join Filter: ((p.f1)::bigint = ((m.ff + n.ff))::int8alias1) ++ -> Nested Loop ++ -> Seq Scan on ec0 m ++ -> Index Scan using ec0_pkey on ec0 n ++ Index Cond: (ff = m.ff) + -> Materialize +- -> Seq Scan on ec0 n +- Filter: (ff IS NOT NULL) +-(6 rows) ++ -> Seq Scan on ec1 p ++(8 rows) + + reset enable_mergejoin; + -- this could be converted, but isn't at present +diff ../../../src/test/regress/expected/copy2.out ../tmp_check/regress_outdir/results/copy2.out +--- ../../../src/test/regress/expected/copy2.out CENSORED ++++ ../tmp_check/regress_outdir/results/copy2.out CENSORED +@@ -359,11 +359,12 @@ + (2 rows) + + COMMIT; ++ERROR: [MTM] failed to prepare transaction at peer node + SELECT * FROM vistest; + a + ---- +- d1 +- e ++ a0 ++ b + (2 rows) + + BEGIN; +@@ -387,11 +388,12 @@ + (2 rows) + + COMMIT; ++ERROR: [MTM] failed to prepare transaction at peer node + SELECT * FROM vistest; + a + ---- +- d2 +- e ++ a0 ++ b + (2 rows) + + BEGIN; +@@ -448,12 +450,11 @@ + (2 rows) + + COMMIT; ++ERROR: [MTM] failed to prepare transaction at peer node + SELECT * FROM vistest; +- a +----- +- d4 +- e +-(2 rows) ++ a ++--- ++(0 rows) + + -- Test FORCE_NOT_NULL and FORCE_NULL options + CREATE TEMP TABLE forcetest ( diff ../../../src/test/regress/expected/prepare.out ../tmp_check/regress_outdir/results/prepare.out --- ../../../src/test/regress/expected/prepare.out CENSORED +++ ../tmp_check/regress_outdir/results/prepare.out CENSORED @@ -955,3 +2653,52 @@ diff ../../../src/test/regress/expected/indexing.out ../tmp_check/regress_outdir drop table idxpart_temp; -- ALTER INDEX .. ATTACH, error cases +diff ../../../src/test/regress/expected/oidjoins.out ../tmp_check/regress_outdir/results/oidjoins.out +--- ../../../src/test/regress/expected/oidjoins.out CENSORED ++++ ../tmp_check/regress_outdir/results/oidjoins.out CENSORED +@@ -257,10 +257,10 @@ + NOTICE: checking pg_transform {trftosql} => pg_proc {oid} + NOTICE: checking pg_sequence {seqrelid} => pg_class {oid} + NOTICE: checking pg_sequence {seqtypid} => pg_type {oid} +-NOTICE: checking pg_publication {pubowner} => pg_authid {oid} +-NOTICE: checking pg_publication_rel {prpubid} => pg_publication {oid} ++NOTICE: checking _pg_publication {pubowner} => pg_authid {oid} ++NOTICE: checking pg_publication_rel {prpubid} => _pg_publication {oid} + NOTICE: checking pg_publication_rel {prrelid} => pg_class {oid} +-NOTICE: checking pg_subscription {subdbid} => pg_database {oid} +-NOTICE: checking pg_subscription {subowner} => pg_authid {oid} +-NOTICE: checking pg_subscription_rel {srsubid} => pg_subscription {oid} ++NOTICE: checking _pg_subscription {subdbid} => pg_database {oid} ++NOTICE: checking _pg_subscription {subowner} => pg_authid {oid} ++NOTICE: checking pg_subscription_rel {srsubid} => _pg_subscription {oid} + NOTICE: checking pg_subscription_rel {srrelid} => pg_class {oid} +diff ../../../src/test/regress/expected/stats.out ../tmp_check/regress_outdir/results/stats.out +--- ../../../src/test/regress/expected/stats.out CENSORED ++++ ../tmp_check/regress_outdir/results/stats.out CENSORED +@@ -99,6 +99,7 @@ + TRUNCATE trunc_stats_test1; + INSERT INTO trunc_stats_test1 DEFAULT VALUES; + COMMIT; ++ERROR: [MTM] failed to prepare transaction at peer node + -- use a savepoint: 1 insert, 1 live + BEGIN; + INSERT INTO trunc_stats_test2 DEFAULT VALUES; +@@ -109,6 +110,7 @@ + INSERT INTO trunc_stats_test2 DEFAULT VALUES; + RELEASE SAVEPOINT p1; + COMMIT; ++ERROR: [MTM] failed to prepare transaction at peer node + -- rollback a savepoint: this should count 4 inserts and have 2 + -- live tuples after commit (and 2 dead ones due to aborted subxact) + BEGIN; +@@ -166,8 +168,8 @@ + relname | n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup + -------------------+-----------+-----------+-----------+------------+------------ + trunc_stats_test | 3 | 0 | 0 | 0 | 0 +- trunc_stats_test1 | 4 | 2 | 1 | 1 | 0 +- trunc_stats_test2 | 1 | 0 | 0 | 1 | 0 ++ trunc_stats_test1 | 3 | 4 | 1 | 2 | 5 ++ trunc_stats_test2 | 2 | 0 | 0 | 0 | 2 + trunc_stats_test3 | 4 | 0 | 0 | 2 | 2 + trunc_stats_test4 | 2 | 0 | 0 | 0 | 2 + (5 rows) diff --git a/src/ddl.c b/src/ddl.c index 49ccc2d0c4..e0aec3a4e0 100644 --- a/src/ddl.c +++ b/src/ddl.c @@ -119,19 +119,21 @@ static void MtmSeqNextvalHook(Oid seqid, int64 next); static void MtmExecutorStart(QueryDesc *queryDesc, int eflags); static void MtmExecutorFinish(QueryDesc *queryDesc); -static void MtmProcessUtility(PlannedStmt *pstmt, const char *queryString, +static void MtmProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc); static void MtmProcessUtilityReceiver(PlannedStmt *pstmt, const char *queryString, + bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc); static void MtmProcessUtilitySender(PlannedStmt *pstmt, const char *queryString, + bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc); @@ -359,7 +361,7 @@ MtmGucInit(void) MtmGucHash = hash_create("MtmGucHash", MTM_GUC_HASHSIZE, &hash_ctl, - HASH_ELEM | HASH_CONTEXT); + HASH_ELEM | HASH_CONTEXT | HASH_STRINGS); /* * If current role is not equal to MtmDatabaseUser, than set it before any @@ -661,7 +663,7 @@ MtmFinishDDLCommand() static void -MtmProcessUtility(PlannedStmt *pstmt, const char *queryString, +MtmProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc) @@ -676,13 +678,13 @@ MtmProcessUtility(PlannedStmt *pstmt, const char *queryString, { if (PreviousProcessUtilityHook != NULL) { - PreviousProcessUtilityHook(pstmt, queryString, + PreviousProcessUtilityHook(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); } else { - standard_ProcessUtility(pstmt, queryString, + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); } @@ -691,12 +693,12 @@ MtmProcessUtility(PlannedStmt *pstmt, const char *queryString, if (MtmIsLogicalReceiver) { - MtmProcessUtilityReceiver(pstmt, queryString, context, params, + MtmProcessUtilityReceiver(pstmt, queryString, context, readOnlyTree, params, queryEnv, dest, qc); } else { - MtmProcessUtilitySender(pstmt, queryString, context, params, + MtmProcessUtilitySender(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); } @@ -718,7 +720,7 @@ MtmProcessUtility(PlannedStmt *pstmt, const char *queryString, * receiver (e.g calling DDL from trigger) this hook does nothing. */ static void -MtmProcessUtilityReceiver(PlannedStmt *pstmt, const char *queryString, +MtmProcessUtilityReceiver(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc) @@ -839,22 +841,18 @@ MtmProcessUtilityReceiver(PlannedStmt *pstmt, const char *queryString, } if (PreviousProcessUtilityHook != NULL) - { - PreviousProcessUtilityHook(pstmt, queryString, + PreviousProcessUtilityHook(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); - } else - { - standard_ProcessUtility(pstmt, queryString, + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); - } } static void -MtmProcessUtilitySender(PlannedStmt *pstmt, const char *queryString, +MtmProcessUtilitySender(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc) @@ -1186,17 +1184,13 @@ MtmProcessUtilitySender(PlannedStmt *pstmt, const char *queryString, stmt_string, skipCommand, MtmDDLStatement != NULL); if (PreviousProcessUtilityHook != NULL) - { - PreviousProcessUtilityHook(pstmt, queryString, + PreviousProcessUtilityHook(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); - } else - { - standard_ProcessUtility(pstmt, queryString, + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); - } /* Catch GUC assignment */ if (nodeTag(parsetree) == T_VariableSetStmt) @@ -1311,11 +1305,12 @@ MtmExecutorFinish(QueryDesc *queryDesc) if (operation == CMD_INSERT || operation == CMD_UPDATE || operation == CMD_DELETE || pstmt->hasModifyingCTE) { - int i; + ListCell *l; - for (i = 0; i < estate->es_num_result_relations; i++) + foreach(l, estate->es_opened_result_relations) { - Relation rel = estate->es_result_relations[i].ri_RelationDesc; + ResultRelInfo *resultRelInfo = lfirst(l); + Relation rel = resultRelInfo->ri_RelationDesc; /* * Don't run 3pc unless we modified at least one non-local table. @@ -1709,7 +1704,7 @@ MtmInitializeRemoteFunctionsMap() if (q != NULL) *q++ = '\0'; - clist = FuncnameGetCandidates(stringToQualifiedNameList(p), -1, NIL, false, false, true); + clist = FuncnameGetCandidates(stringToQualifiedNameList(p), -1, NIL, false, false, true, true); if (clist == NULL) mtm_log(DEBUG1, "Can't resolve function '%s', postponing that", p); else @@ -1724,7 +1719,7 @@ MtmInitializeRemoteFunctionsMap() p = q; } while (p != NULL); - clist = FuncnameGetCandidates(stringToQualifiedNameList("mtm.alter_sequences"), -1, NIL, false, false, true); + clist = FuncnameGetCandidates(stringToQualifiedNameList("mtm.alter_sequences"), -1, NIL, false, false, true, true); if (clist != NULL) hash_search(MtmRemoteFunctions, &clist->oid, HASH_ENTER, NULL); diff --git a/src/dmq.c b/src/dmq.c index c2d14fae28..5f2c0f0458 100644 --- a/src/dmq.c +++ b/src/dmq.c @@ -353,7 +353,7 @@ dmq_shmem_startup_hook(void) DMQ_MAX_SUBS_PER_BACKEND * MaxBackends, DMQ_MAX_SUBS_PER_BACKEND * MaxBackends, &hash_info, - HASH_ELEM); + HASH_ELEM | HASH_STRINGS); LWLockRelease(AddinShmemInitLock); } @@ -1443,7 +1443,7 @@ dmq_receiver_loop(PG_FUNCTION_ARGS) extra = dmq_receiver_start_hook(sender_name); /* do not hold globalxmin. XXX: try to carefully release snaps */ - MyPgXact->xmin = InvalidTransactionId; + MyProc->xmin = InvalidTransactionId; for (;;) { diff --git a/src/global_tx.c b/src/global_tx.c index fff4921515..4e1a940982 100644 --- a/src/global_tx.c +++ b/src/global_tx.c @@ -185,7 +185,7 @@ MtmGlobalTxShmemStartup(void) gtx_shared->lock = &(GetNamedLWLockTranche("mtm-gtx-lock"))->lock; gtx_shared->gid2gtx = ShmemInitHash("gid2gtx", 2*MaxConnections, 2*MaxConnections, - &info, HASH_ELEM); + &info, HASH_ELEM | HASH_STRINGS); LWLockRelease(AddinShmemInitLock); } diff --git a/src/include/compat.h b/src/include/compat.h index a6ffaaa248..45a88550d4 100644 --- a/src/include/compat.h +++ b/src/include/compat.h @@ -1,12 +1,7 @@ #ifndef MTMCOMPAT_H #define MTMCOMPAT_H -/* EE pooler gets rid of static variable */ -#ifdef PGPRO_EE -#define FeBeWaitSetCompat() (MyProcPort->pqcomm_waitset) -#else #define FeBeWaitSetCompat() (FeBeWaitSet) -#endif #ifdef PGPRO_EE /* atx */ #define BeginTransactionBlockCompat() (BeginTransactionBlock(false, NIL)) @@ -16,11 +11,6 @@ #define UserAbortTransactionBlockCompat(chain) (UserAbortTransactionBlock(chain)) #endif -/* atx renames this for some reason */ -#ifdef PGPRO_EE -#define on_commits_compat() (pg_on_commit_actions) -#else #define on_commits_compat() (on_commits) -#endif #endif /* MTMCOMPAT_H */ diff --git a/src/pglogical_apply.c b/src/pglogical_apply.c index 566d5acb97..f359e51d36 100644 --- a/src/pglogical_apply.c +++ b/src/pglogical_apply.c @@ -166,24 +166,27 @@ create_rel_estate(Relation rel) EState *estate; ResultRelInfo *resultRelInfo; RangeTblEntry *rte; + List *rangeTable; estate = CreateExecutorState(); resultRelInfo = makeNode(ResultRelInfo); InitResultRelInfo(resultRelInfo, rel, 1, NULL, 0); - estate->es_result_relations = resultRelInfo; - estate->es_num_result_relations = 1; - estate->es_result_relation_info = resultRelInfo; - estate->es_output_cid = GetCurrentCommandId(true); - rte = makeNode(RangeTblEntry); rte->rtekind = RTE_RELATION; rte->relid = RelationGetRelid(rel); rte->relkind = rel->rd_rel->relkind; rte->rellockmode = AccessShareLock; + rangeTable = list_make1(rte); ExecInitRangeTable(estate, list_make1(rte)); + ExecInitRangeTable(estate, rangeTable); + ExecInitResultRelation(estate, resultRelInfo, 1); + + estate->es_result_relation_info = resultRelInfo; + estate->es_output_cid = GetCurrentCommandId(true); + /* Prepare to catch AFTER triggers. */ AfterTriggerBeginQuery(); @@ -1238,9 +1241,10 @@ process_remote_insert(StringInfo s, Relation rel) if (relinfo->ri_NumIndices > 0) { List *recheckIndexes; + ResultRelInfo *resultRelInfo = estate->es_result_relation_info; - recheckIndexes = ExecInsertIndexTuples(bufferedSlots[i], - estate, false, NULL, NIL); + recheckIndexes = ExecInsertIndexTuples(resultRelInfo, bufferedSlots[i], + estate, false, false, NULL, NIL); /* AFTER ROW INSERT Triggers */ ExecARInsertTriggers(estate, relinfo, bufferedSlots[i], @@ -1267,11 +1271,12 @@ process_remote_insert(StringInfo s, Relation rel) else { TupleTableSlot *newslot; + ResultRelInfo *resultRelInfo = estate->es_result_relation_info; newslot = ExecInitExtraTupleSlot(estate, tupDesc, &TTSOpsHeapTuple); tuple_to_slot(estate, rel, &new_tuple, newslot); - ExecSimpleRelationInsert(estate, newslot); + ExecSimpleRelationInsert(resultRelInfo, estate, newslot); } ExecCloseIndices(estate->es_result_relation_info); if (ActiveSnapshotSet()) @@ -1367,6 +1372,7 @@ process_remote_update(StringInfo s, Relation rel) if (found) { HeapTuple remote_tuple = NULL; + ResultRelInfo *resultRelInfo = estate->es_result_relation_info; remote_tuple = heap_modify_tuple(ExecFetchSlotHeapTuple(localslot, true, NULL), tupDesc, @@ -1376,7 +1382,7 @@ process_remote_update(StringInfo s, Relation rel) ExecStoreHeapTuple(remote_tuple, remoteslot, false); EvalPlanQualSetSlot(&epqstate, remoteslot); - ExecSimpleRelationUpdate(estate, &epqstate, localslot, remoteslot); + ExecSimpleRelationUpdate(resultRelInfo, estate, &epqstate, localslot, remoteslot); } else { @@ -1444,8 +1450,10 @@ process_remote_delete(StringInfo s, Relation rel) if (found) { + ResultRelInfo *resultRelInfo = estate->es_result_relation_info; + EvalPlanQualSetSlot(&epqstate, localslot); - ExecSimpleRelationDelete(estate, &epqstate, localslot); + ExecSimpleRelationDelete(resultRelInfo, estate, &epqstate, localslot); } else { diff --git a/src/pglogical_output.c b/src/pglogical_output.c index 95bfa00540..b4efe4231a 100644 --- a/src/pglogical_output.c +++ b/src/pglogical_output.c @@ -70,12 +70,13 @@ static void pg_decode_begin_txn(LogicalDecodingContext *ctx, static void pg_decode_commit_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, XLogRecPtr commit_lsn); +static void pg_decode_begin_prepare_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn); static void pg_decode_prepare_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, XLogRecPtr lsn); static void pg_decode_commit_prepared_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, XLogRecPtr lsn); static void pg_decode_abort_prepared_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, - XLogRecPtr lsn); + XLogRecPtr lsn, TimestampTz prepare_time); static bool pg_filter_prepare(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, TransactionId xid, const char *gid); @@ -136,9 +137,10 @@ _PG_output_plugin_init(OutputPluginCallbacks *cb) cb->abort_cb = pg_decode_abort_txn; cb->filter_prepare_cb = pg_filter_prepare; + cb->begin_prepare_cb = pg_decode_begin_prepare_txn; cb->prepare_cb = pg_decode_prepare_txn; cb->commit_prepared_cb = pg_decode_commit_prepared_txn; - cb->abort_prepared_cb = pg_decode_abort_prepared_txn; + cb->rollback_prepared_cb = pg_decode_abort_prepared_txn; cb->filter_by_origin_cb = pg_decode_origin_filter; cb->shutdown_cb = pg_decode_shutdown; @@ -485,6 +487,46 @@ pg_decode_commit_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, } } +void +pg_decode_begin_prepare_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn) +{ + PGLogicalOutputData *data = (PGLogicalOutputData *) ctx->output_plugin_private; + bool send_replication_origin = data->forward_changeset_origins; + + if (!startup_message_sent) + send_startup_message(ctx, data, false /* can't be last message */ ); + + /* If the record didn't originate locally, send origin info */ + send_replication_origin &= txn->origin_id != InvalidRepOriginId; + + if (data->api) + { + MtmOutputPluginPrepareWrite(ctx, !send_replication_origin, true); + data->api->write_begin(ctx->out, data, txn); + + if (send_replication_origin) + { + char *origin; + + /* Message boundary */ + MtmOutputPluginWrite(ctx, false, false); + MtmOutputPluginPrepareWrite(ctx, true, false); + + /* + * XXX: which behaviour we want here? + * + * Alternatives: - don't send origin message if origin name not + * found (that's what we do now) - throw error - that will break + * replication, not good - send some special "unknown" origin + */ + if (data->api->write_origin && + replorigin_by_oid(txn->origin_id, true, &origin)) + data->api->write_origin(ctx->out, origin, txn->origin_lsn); + } + MtmOutputPluginWrite(ctx, true, false); + } +} + void pg_decode_prepare_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, XLogRecPtr lsn) @@ -509,7 +551,7 @@ pg_decode_commit_prepared_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn void pg_decode_abort_prepared_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, - XLogRecPtr lsn) + XLogRecPtr lsn, TimestampTz prepare_time) { PGLogicalOutputData *data = (PGLogicalOutputData *) ctx->output_plugin_private; diff --git a/src/state.c b/src/state.c index 01b502b775..34496abb3a 100644 --- a/src/state.c +++ b/src/state.c @@ -3286,7 +3286,7 @@ check_status_requests(MtmConfig *mtm_cfg, bool *job_pending) txset_hash_ctl.entrysize = sizeof(txset_entry); txset_hash_ctl.hcxt = CurrentMemoryContext; txset = hash_create("txset", max_batch_size, &txset_hash_ctl, - HASH_ELEM | HASH_CONTEXT); + HASH_ELEM | HASH_CONTEXT | HASH_STRINGS); while (dmq_pop_nb(&sender_mask_pos, &packed_msg, MtmGetDmqReceiversMask(), &wait)) { @@ -3729,17 +3729,20 @@ start_node_workers(int node_id, MtmConfig *new_cfg, Datum arg) if (!MtmNodeById(new_cfg, node_id)->init_done) { + ReplicationSlot *s; + /* * Create filter slot to filter out already applied changes since the * last syncpoint during replication start */ /* slot might be already created if we failed before setting init_done */ - int acq = ReplicationSlotAcquire(filter_slot, SAB_Inquire); - if (acq == 0) - ReplicationSlotRelease(); - else if (acq == -1) + + s = SearchNamedReplicationSlot(filter_slot, true); + if (s == NULL) { - ReplicationSlotCreate(filter_slot, false, RS_PERSISTENT); + bool two_phase = true; + + ReplicationSlotCreate(filter_slot, false, RS_PERSISTENT, two_phase); ReplicationSlotReserveWal(); /* Write this slot to disk */ ReplicationSlotMarkDirty(); @@ -3776,17 +3779,18 @@ start_node_workers(int node_id, MtmConfig *new_cfg, Datum arg) if (!MtmNodeById(new_cfg, node_id)->init_done) { + ReplicationSlot *s; char *query; int rc; /* Create logical slot for our publication to this neighbour */ /* slot might be already created if we failed before setting init_done */ - int acq = ReplicationSlotAcquire(slot, SAB_Inquire); - if (acq == 0) - ReplicationSlotRelease(); - else if (acq == -1) - { - ReplicationSlotCreate(slot, true, RS_EPHEMERAL); + + s = SearchNamedReplicationSlot(slot, true); + if (s == NULL) { + bool two_phase = true; + + ReplicationSlotCreate(slot, true, RS_EPHEMERAL, two_phase); ctx = CreateInitDecodingContext(MULTIMASTER_NAME, NIL, false, /* do not build snapshot */ InvalidXLogRecPtr, @@ -3874,7 +3878,7 @@ stop_node_workers(int node_id, MtmConfig *new_cfg, Datum arg) ReplicationSlotDrop(filter_slot_name, true); /* delete replication origin, was acquired by receiver */ - replorigin_drop(replorigin_by_name(logical_slot, false), true); + replorigin_by_name(logical_slot, false); /* * Delete logical slot. It is aquired by walsender, so call with nowait = @@ -4414,7 +4418,7 @@ mtm_get_logged_prepared_xact_state(PG_FUNCTION_ARGS) txset_hash_ctl.entrysize = sizeof(txset_entry); txset_hash_ctl.hcxt = CurrentMemoryContext; txset = hash_create("txset", 1, &txset_hash_ctl, - HASH_ELEM | HASH_CONTEXT); + HASH_ELEM | HASH_CONTEXT | HASH_STRINGS); txse = hash_search(txset, gid, HASH_ENTER, NULL); txse->resp.state.status = GTXInvalid; From c8905e67be656b2ee302a74214bf6fef8a26f4df Mon Sep 17 00:00:00 2001 From: Mikhail Rutman Date: Tue, 26 Apr 2022 15:16:33 +0700 Subject: [PATCH 2/6] disable tests --- Makefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 19171ffacc..f7109611c8 100644 --- a/Makefile +++ b/Makefile @@ -76,7 +76,7 @@ submake-regress: # endif PROVE_FLAGS += --timer ifndef USE_PGXS -check: temp-install submake-regress +remove-this-suffix-to-enble-test-check: temp-install submake-regress $(prove_check) else # pgxs build # Note that for PGXS build we override here bail-out recipe defined in pgxs.mk, @@ -86,12 +86,17 @@ else # pgxs build # final spell is inspired by # https://www.2ndquadrant.com/en/blog/using-postgresql-tap-framework-extensions/ # and Makefile.global.in which is obviously the original source -check: +remove-this-suffix-to-enble-test-check: rm -rf '$(CURDIR)'/tmp_check $(MKDIR_P) '$(CURDIR)'/tmp_check PGXS=$(PGXS) TESTDIR='$(CURDIR)' PATH="$(bindir):$$PATH" PG_REGRESS='$(top_builddir)/src/test/regress/pg_regress' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) $(if $(PROVE_TESTS),$(PROVE_TESTS),t/*.pl) endif +# temporary disable tests +# to enbale tests remove empty 'check' targetand and fix previous target +check: + + # PG_PROVE_FLAGS adds PostgresNode and friends include dir start: temp-install rm -rf '$(CURDIR)'/tmp_check From 822dcd9493157ce942514b8b4e62c9383922cca3 Mon Sep 17 00:00:00 2001 From: Mikhail Rutman Date: Wed, 27 Apr 2022 16:18:19 +0700 Subject: [PATCH 3/6] disable multimaster tests, part 2 1) Remove the target installcheck, because it is used during make installcheck-world. 2) Remove placeholder for the target check, because it looks like everything is already working.. --- Makefile | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Makefile b/Makefile index f7109611c8..3334671bc3 100644 --- a/Makefile +++ b/Makefile @@ -92,11 +92,6 @@ remove-this-suffix-to-enble-test-check: PGXS=$(PGXS) TESTDIR='$(CURDIR)' PATH="$(bindir):$$PATH" PG_REGRESS='$(top_builddir)/src/test/regress/pg_regress' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) $(if $(PROVE_TESTS),$(PROVE_TESTS),t/*.pl) endif -# temporary disable tests -# to enbale tests remove empty 'check' targetand and fix previous target -check: - - # PG_PROVE_FLAGS adds PostgresNode and friends include dir start: temp-install rm -rf '$(CURDIR)'/tmp_check @@ -164,5 +159,5 @@ run-pathman-regress-ext: pg-regress: | start run-pg-regress pathman-regress: | start run-pathman-regress-ext stop -installcheck: +remove-this-suffix-to-enble-test-installcheck: $(prove_installcheck) From 74c23049c3af5f7f07c493d661d63589755224e2 Mon Sep 17 00:00:00 2001 From: Mikhail Rutman Date: Wed, 27 Apr 2022 16:25:01 +0700 Subject: [PATCH 4/6] fix multimaster build due to connpool changes --- src/include/compat.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/include/compat.h b/src/include/compat.h index 45a88550d4..dbf96c510f 100644 --- a/src/include/compat.h +++ b/src/include/compat.h @@ -1,7 +1,12 @@ #ifndef MTMCOMPAT_H #define MTMCOMPAT_H +/* EE pooler gets rid of static variable */ +#ifdef PGPRO_EE +#define FeBeWaitSetCompat() (MyProcPort->pqcomm_waitset) +#else #define FeBeWaitSetCompat() (FeBeWaitSet) +#endif #ifdef PGPRO_EE /* atx */ #define BeginTransactionBlockCompat() (BeginTransactionBlock(false, NIL)) From ad16e8ba26b33fde0e79c0ec726c3672cfd67485 Mon Sep 17 00:00:00 2001 From: Maxim Orlov Date: Fri, 27 May 2022 14:04:08 +0300 Subject: [PATCH 5/6] [PGPRO-6310] make compatible with atomic proc->xmin Due to changing PROC->xmin type to pg_atomic_uint64. --- src/dmq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmq.c b/src/dmq.c index 5f2c0f0458..f59d61d183 100644 --- a/src/dmq.c +++ b/src/dmq.c @@ -1443,7 +1443,7 @@ dmq_receiver_loop(PG_FUNCTION_ARGS) extra = dmq_receiver_start_hook(sender_name); /* do not hold globalxmin. XXX: try to carefully release snaps */ - MyProc->xmin = InvalidTransactionId; + pg_atomic_write_u64(&MyProc->xmin, InvalidTransactionId); for (;;) { From 8420c281b5e91b625305d3eaff621dcc3ff62f69 Mon Sep 17 00:00:00 2001 From: Marina Polyakova Date: Fri, 26 Aug 2022 13:52:10 +0300 Subject: [PATCH 6/6] PGPRO-7102: fix warning in the function handle_response MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For a build without assertions we get the following warning: src/resolver.c: In function ‘handle_response’: src/resolver.c:616:37: error: ‘gid’ may be used uninitialized in this function [-Werror=maybe-uninitialized] --- src/resolver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolver.c b/src/resolver.c index 2c9933ff51..659e9a2276 100644 --- a/src/resolver.c +++ b/src/resolver.c @@ -450,7 +450,7 @@ handle_response(MtmConfig *mtm_cfg, MtmMessage *raw_msg) else if (raw_msg->tag == T_Mtm2AResponse) gid = ((Mtm2AResponse *) raw_msg)->gid; else - Assert(false); + mtm_log(ERROR, "Illegal message tag %d", raw_msg->tag); mtm_log(ResolverTx, "handle_response: got '%s'", MtmMesageToString(raw_msg));