diff options
| -rw-r--r-- | src/backend/catalog/namespace.c | 3 | ||||
| -rw-r--r-- | src/backend/catalog/system_views.sql | 7 | ||||
| -rw-r--r-- | src/backend/pgxc/locator/locator.c | 32 | ||||
| -rw-r--r-- | src/backend/postmaster/postmaster.c | 20 | ||||
| -rw-r--r-- | src/backend/utils/misc/guc.c | 17 | ||||
| -rw-r--r-- | src/include/pgxc/locator.h | 4 | ||||
| -rw-r--r-- | src/test/regress/expected/prepared_xacts_2.out | 230 | ||||
| -rw-r--r-- | src/test/regress/sql/prepared_xacts.sql | 24 |
8 files changed, 327 insertions, 10 deletions
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index e2e1998550..ee83d37921 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -51,6 +51,9 @@ #include "utils/rel.h" #include "utils/syscache.h" +#ifdef PGXC +#include "pgxc/pgxc.h" +#endif /* * The namespace search path is a possibly-empty list of namespace OIDs. diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 8be3defe75..2edaf48953 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -150,7 +150,12 @@ CREATE VIEW pg_locks AS CREATE VIEW pg_cursors AS SELECT * FROM pg_cursor() AS C; -CREATE VIEW pg_prepared_xacts AS +CREATE SCHEMA __pgxc_coordinator_schema__; +CREATE SCHEMA __pgxc_datanode_schema__; + +create table __pgxc_coordinator_schema__.pg_prepared_xacts ( transaction xid, gid text, prepared timestamptz, owner name, database name ); + +CREATE VIEW __pgxc_datanode_schema__.pg_prepared_xacts AS SELECT P.transaction, P.gid, P.prepared, U.rolname AS owner, D.datname AS database FROM pg_prepared_xact() AS P diff --git a/src/backend/pgxc/locator/locator.c b/src/backend/pgxc/locator/locator.c index d1aef8b348..4116476fbf 100644 --- a/src/backend/pgxc/locator/locator.c +++ b/src/backend/pgxc/locator/locator.c @@ -750,9 +750,41 @@ RelationLocInfo * GetRelationLocInfo(Oid relid) { RelationLocInfo *ret_loc_info = NULL; + char *namespace; Relation rel = relation_open(relid, AccessShareLock); + /* This check has been added as a temp fix for CREATE TABLE not adding entry in pgxc_class + * when run from system_views.sql + */ + if ( rel != NULL && + rel->rd_rel != NULL && + rel->rd_rel->relkind == RELKIND_RELATION && + rel->rd_rel->relname.data != NULL && + (strcmp(rel->rd_rel->relname.data, PREPARED_XACTS_TABLE) == 0) ) + { + namespace = get_namespace_name(rel->rd_rel->relnamespace); + + if (namespace != NULL && (strcmp(namespace, PGXC_COORDINATOR_SCHEMA) == 0)) + { + RelationLocInfo *dest_info; + + dest_info = (RelationLocInfo *) palloc0(sizeof(RelationLocInfo)); + + dest_info->relid = relid; + dest_info->locatorType = 'N'; + dest_info->nodeCount = NumDataNodes; + dest_info->nodeList = GetAllDataNodes(); + + relation_close(rel, AccessShareLock); + pfree(namespace); + + return dest_info; + } + + if (namespace != NULL) pfree(namespace); + } + if (rel && rel->rd_locator_info) ret_loc_info = CopyRelationLocInfo(rel->rd_locator_info); diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 90f8ff7701..b39dda0f8e 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -538,6 +538,26 @@ PostmasterMain(int argc, char *argv[]) /* Initialize paths to installation files */ getInstallationPaths(argv[0]); +#ifdef PGXC + /* Decide whether coordinator or data node before setting GUC variables */ + while ((opt = getopt(argc, argv, "A:B:Cc:D:d:EeFf:h:ijk:lN:nOo:Pp:r:S:sTt:W:X-:")) != -1) + { + switch (opt) + { + case 'C': + isPGXCCoordinator = true; + break; + case 'X': + isPGXCDataNode = true; + break; + default: + break; + } + } + /* Reset getopt for parsing again */ + optind = 1; +#endif + /* * Options setup */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index c4521fd104..869a172156 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2235,6 +2235,10 @@ static struct config_int ConfigureNamesInt[] = } }; +#ifdef PGXC +/* Variable to store search path */ +static char boot_search_path[255]; +#endif static struct config_real ConfigureNamesReal[] = { @@ -2363,7 +2367,6 @@ static struct config_real ConfigureNamesReal[] = } }; - static struct config_string ConfigureNamesString[] = { { @@ -2560,7 +2563,11 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT | GUC_LIST_QUOTE }, &namespace_search_path, +#ifdef PGXC + boot_search_path, assign_search_path, NULL +#else "\"$user\",public", assign_search_path, NULL +#endif }, { @@ -3291,6 +3298,14 @@ build_guc_variables(void) struct config_generic **guc_vars; int i; +#ifdef PGXC + strcpy(boot_search_path, "\"$user\",public, "); + if (IS_PGXC_DATANODE) + strcat(boot_search_path, PGXC_DATA_NODE_SCHEMA); + else + strcat(boot_search_path, PGXC_COORDINATOR_SCHEMA); +#endif + for (i = 0; ConfigureNamesBool[i].gen.name; i++) { struct config_bool *conf = &ConfigureNamesBool[i]; diff --git a/src/include/pgxc/locator.h b/src/include/pgxc/locator.h index 3272ab6cb1..9f669d92e0 100644 --- a/src/include/pgxc/locator.h +++ b/src/include/pgxc/locator.h @@ -28,6 +28,10 @@ #define IsReplicated(x) (x->locatorType == LOCATOR_TYPE_REPLICATED) +#define PGXC_COORDINATOR_SCHEMA "__pgxc_coordinator_schema__" +#define PGXC_DATA_NODE_SCHEMA "__pgxc_datanode_schema__" +#define PREPARED_XACTS_TABLE "pg_prepared_xacts" + #include "nodes/primnodes.h" #include "utils/relcache.h" diff --git a/src/test/regress/expected/prepared_xacts_2.out b/src/test/regress/expected/prepared_xacts_2.out new file mode 100644 index 0000000000..e4562001df --- /dev/null +++ b/src/test/regress/expected/prepared_xacts_2.out @@ -0,0 +1,230 @@ +-- +-- PREPARED TRANSACTIONS (two-phase commit) +-- +-- We can't readily test persistence of prepared xacts within the +-- regression script framework, unfortunately. Note that a crash +-- isn't really needed ... stopping and starting the postmaster would +-- be enough, but we can't even do that here. +-- create a simple table that we'll use in the tests +CREATE TABLE pxtest1 (foobar VARCHAR(10)); +INSERT INTO pxtest1 VALUES ('aaa'); +-- Test PREPARE TRANSACTION +BEGIN; +UPDATE pxtest1 SET foobar = 'bbb' WHERE foobar = 'aaa'; +SELECT * FROM pxtest1 ORDER BY foobar; + foobar +-------- + bbb +(1 row) + +PREPARE TRANSACTION 'foo1'; +SELECT * FROM pxtest1 ORDER BY foobar; + foobar +-------- + aaa +(1 row) + +-- Test pg_prepared_xacts system view +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; + gid +------ + foo1 +(1 row) + +-- Test ROLLBACK PREPARED +ROLLBACK PREPARED 'foo1'; +SELECT * FROM pxtest1 ORDER BY foobar; + foobar +-------- + aaa +(1 row) + +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; + gid +----- +(0 rows) + +-- Test COMMIT PREPARED +BEGIN; +INSERT INTO pxtest1 VALUES ('ddd'); +SELECT * FROM pxtest1 ORDER BY foobar; + foobar +-------- + aaa + ddd +(2 rows) + +PREPARE TRANSACTION 'foo2'; +SELECT * FROM pxtest1 ORDER BY foobar; + foobar +-------- + aaa +(1 row) + +COMMIT PREPARED 'foo2'; +SELECT * FROM pxtest1 ORDER BY foobar; + foobar +-------- + aaa + ddd +(2 rows) + +-- Test duplicate gids +BEGIN; +UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd'; +SELECT * FROM pxtest1 ORDER BY foobar; + foobar +-------- + aaa + eee +(2 rows) + +PREPARE TRANSACTION 'foo3'; +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; + gid +------ + foo3 +(1 row) + +BEGIN; +INSERT INTO pxtest1 VALUES ('fff'); +SELECT * FROM pxtest1 ORDER BY foobar; + foobar +-------- + aaa + ddd + fff +(3 rows) + +-- This should fail, because the gid foo3 is already in use +PREPARE TRANSACTION 'foo3'; +ERROR: Could not prepare transaction on data nodes +ROLLBACK; +SELECT * FROM pxtest1 ORDER BY foobar; + foobar +-------- + aaa + ddd +(2 rows) + +ROLLBACK PREPARED 'foo3'; +SELECT * FROM pxtest1 ORDER BY foobar; + foobar +-------- + aaa + ddd +(2 rows) + +-- Clean up +DROP TABLE pxtest1; +-- Test subtransactions +BEGIN; + CREATE TABLE pxtest2 (a int); + INSERT INTO pxtest2 VALUES (1); + SAVEPOINT a; +ERROR: SAVEPOINT is not yet supported. + INSERT INTO pxtest2 VALUES (2); +ERROR: current transaction is aborted, commands ignored until end of transaction block + ROLLBACK TO a; +ERROR: no such savepoint + SAVEPOINT b; +ERROR: current transaction is aborted, commands ignored until end of transaction block + INSERT INTO pxtest2 VALUES (3); +ERROR: current transaction is aborted, commands ignored until end of transaction block +PREPARE TRANSACTION 'regress-one'; +BEGIN; + CREATE TABLE pxtest2 (a int); + INSERT INTO pxtest2 VALUES (1); + INSERT INTO pxtest2 VALUES (3); +PREPARE TRANSACTION 'regress-one'; +CREATE TABLE pxtest3(fff int); +-- Test shared invalidation +BEGIN; + DROP TABLE pxtest3; + CREATE TABLE pxtest4 (a int); + INSERT INTO pxtest4 VALUES (1); + INSERT INTO pxtest4 VALUES (2); + DECLARE foo CURSOR FOR SELECT * FROM pxtest4; + -- Fetch 1 tuple, keeping the cursor open + FETCH 1 FROM foo; + a +--- + 1 +(1 row) + +PREPARE TRANSACTION 'regress-two'; +-- No such cursor +FETCH 1 FROM foo; +ERROR: cursor "foo" does not exist +-- Table doesn't exist, the creation hasn't been committed yet +SELECT * FROM pxtest2; +ERROR: relation "pxtest2" does not exist +LINE 1: SELECT * FROM pxtest2; + ^ +-- There should be two prepared transactions +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; + gid +------------- + regress-one + regress-two +(2 rows) + +-- pxtest3 should be locked because of the pending DROP +set statement_timeout to 2000; +SELECT * FROM pxtest3; +ERROR: canceling statement due to statement timeout +reset statement_timeout; +-- Disconnect, we will continue testing in a different backend +\c - +-- There should still be two prepared transactions +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; + gid +------------- + regress-one + regress-two +(2 rows) + +-- pxtest3 should still be locked because of the pending DROP +set statement_timeout to 2000; +SELECT * FROM pxtest3; +ERROR: canceling statement due to statement timeout +reset statement_timeout; +-- Commit table creation +COMMIT PREPARED 'regress-one'; +\d pxtest2 + Table "public.pxtest2" + Column | Type | Modifiers +--------+---------+----------- + a | integer | + +SELECT * FROM pxtest2; + a +--- + 1 + 3 +(2 rows) + +-- There should be one prepared transaction +SELECT DISTINCT gid FROM pg_prepared_xacts; + gid +------------- + regress-two +(1 row) + +-- Commit table drop +COMMIT PREPARED 'regress-two'; +SELECT * FROM pxtest3; +ERROR: relation "pxtest3" does not exist +LINE 1: SELECT * FROM pxtest3; + ^ +-- There should be no prepared transactions +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; + gid +----- +(0 rows) + +-- Clean up +DROP TABLE pxtest2; +DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled +ERROR: table "pxtest3" does not exist +DROP TABLE pxtest4; diff --git a/src/test/regress/sql/prepared_xacts.sql b/src/test/regress/sql/prepared_xacts.sql index b8915bda77..fb9bc64c8d 100644 --- a/src/test/regress/sql/prepared_xacts.sql +++ b/src/test/regress/sql/prepared_xacts.sql @@ -22,14 +22,14 @@ PREPARE TRANSACTION 'foo1'; SELECT * FROM pxtest1 ORDER BY foobar; -- Test pg_prepared_xacts system view -SELECT gid FROM pg_prepared_xacts ORDER BY gid; +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; -- Test ROLLBACK PREPARED ROLLBACK PREPARED 'foo1'; SELECT * FROM pxtest1 ORDER BY foobar; -SELECT gid FROM pg_prepared_xacts ORDER BY gid; +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; -- Test COMMIT PREPARED @@ -50,7 +50,7 @@ UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd'; SELECT * FROM pxtest1 ORDER BY foobar; PREPARE TRANSACTION 'foo3'; -SELECT gid FROM pg_prepared_xacts ORDER BY gid; +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; BEGIN; INSERT INTO pxtest1 VALUES ('fff'); @@ -59,8 +59,8 @@ SELECT * FROM pxtest1 ORDER BY foobar; -- This should fail, because the gid foo3 is already in use PREPARE TRANSACTION 'foo3'; +ROLLBACK; SELECT * FROM pxtest1 ORDER BY foobar; - ROLLBACK PREPARED 'foo3'; SELECT * FROM pxtest1 ORDER BY foobar; @@ -79,6 +79,13 @@ BEGIN; INSERT INTO pxtest2 VALUES (3); PREPARE TRANSACTION 'regress-one'; +BEGIN; + CREATE TABLE pxtest2 (a int); + INSERT INTO pxtest2 VALUES (1); + INSERT INTO pxtest2 VALUES (3); +PREPARE TRANSACTION 'regress-one'; + + CREATE TABLE pxtest3(fff int); -- Test shared invalidation @@ -99,7 +106,7 @@ FETCH 1 FROM foo; SELECT * FROM pxtest2; -- There should be two prepared transactions -SELECT gid FROM pg_prepared_xacts ORDER BY gid; +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; -- pxtest3 should be locked because of the pending DROP set statement_timeout to 2000; @@ -110,7 +117,7 @@ reset statement_timeout; \c - -- There should still be two prepared transactions -SELECT gid FROM pg_prepared_xacts ORDER BY gid; +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; -- pxtest3 should still be locked because of the pending DROP set statement_timeout to 2000; @@ -123,16 +130,17 @@ COMMIT PREPARED 'regress-one'; SELECT * FROM pxtest2; -- There should be one prepared transaction -SELECT gid FROM pg_prepared_xacts; +SELECT DISTINCT gid FROM pg_prepared_xacts; -- Commit table drop COMMIT PREPARED 'regress-two'; SELECT * FROM pxtest3; -- There should be no prepared transactions -SELECT gid FROM pg_prepared_xacts ORDER BY gid; +SELECT DISTINCT gid FROM pg_prepared_xacts ORDER BY gid; -- Clean up DROP TABLE pxtest2; DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled DROP TABLE pxtest4; + |
