diff options
author | Michael Paquier | 2012-04-29 00:28:23 +0000 |
---|---|---|
committer | Michael Paquier | 2012-04-29 00:28:23 +0000 |
commit | 8c579ff58656330512b4e66a89836ae5f3286b90 (patch) | |
tree | 7e2d8b18811dcfdba867a53bd615645e41c6c4b3 | |
parent | eb356aee558bafed6e2112da117c9eb7f68b1116 (diff) |
Callback mechanism on GTM for sequence renaming
Addition of a callback at transaction abort to change a sequence on GTM
back to its former name in case it has been changed during this transaction.
A new regression test called xc_sequence is added with test cases for
sequence creation and drop callback, and renaming callback.
-rw-r--r-- | src/backend/catalog/dependency.c | 3 | ||||
-rw-r--r-- | src/backend/commands/sequence.c | 74 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 9 | ||||
-rw-r--r-- | src/include/commands/sequence.h | 5 | ||||
-rw-r--r-- | src/test/regress/expected/xc_sequence.out | 178 | ||||
-rw-r--r-- | src/test/regress/parallel_schedule | 2 | ||||
-rw-r--r-- | src/test/regress/serial_schedule | 1 | ||||
-rw-r--r-- | src/test/regress/sql/xc_sequence.sql | 86 |
8 files changed, 356 insertions, 2 deletions
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 9f6b58f31f..f426ecf118 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -392,6 +392,9 @@ doRename(const ObjectAddress *object, const char *oldname, const char *newname) (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("GTM error, could not rename sequence"))); + /* Register a rename callback in case transaction is dropped */ + register_sequence_rename_cb(seqname, newseqname); + pfree(seqname); pfree(newseqname); diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 7647470113..875399b08f 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -101,6 +101,15 @@ typedef struct drop_sequence_callback_arg GTM_SequenceDropType type; GTM_SequenceKeyType key; } drop_sequence_callback_arg; + +/* + * Arguments for callback of sequence rename on GTM + */ +typedef struct rename_sequence_callback_arg +{ + char *newseqname; + char *oldseqname; +} rename_sequence_callback_arg; #endif /* @@ -1902,6 +1911,71 @@ seq_desc(StringInfo buf, uint8 xl_info, char *rec) #ifdef PGXC /* + * Register a callback for a sequence rename drop on GTM + */ +void +register_sequence_rename_cb(char *oldseqname, char *newseqname) +{ + rename_sequence_callback_arg *args; + char *oldseqnamearg = NULL; + char *newseqnamearg = NULL; + + /* All the arguments are transaction-dependent, so save them in TopTransactionContext */ + args = (rename_sequence_callback_arg *) + MemoryContextAlloc(TopTransactionContext, sizeof(rename_sequence_callback_arg)); + + oldseqnamearg = MemoryContextAlloc(TopTransactionContext, strlen(oldseqname) + 1); + newseqnamearg = MemoryContextAlloc(TopTransactionContext, strlen(newseqname) + 1); + sprintf(oldseqnamearg, "%s", oldseqname); + sprintf(newseqnamearg, "%s", newseqname); + + args->oldseqname = oldseqnamearg; + args->newseqname = newseqnamearg; + + RegisterGTMCallback(rename_sequence_cb, (void *) args); +} + +/* + * Callback a sequence rename + */ +void +rename_sequence_cb(GTMEvent event, void *args) +{ + rename_sequence_callback_arg *cbargs = (rename_sequence_callback_arg *) args; + char *newseqname = cbargs->newseqname; + char *oldseqname = cbargs->oldseqname; + int err = 0; + + /* + * A sequence is here renamed to its former name only when a transaction + * that involved a sequence rename was dropped. + */ + switch (event) + { + case GTM_EVENT_ABORT: + /* + * Here sequence is renamed to its former name + * so what was new becomes old. + */ + err = RenameSequenceGTM(newseqname, oldseqname); + break; + case GTM_EVENT_COMMIT: + case GTM_EVENT_PREPARE: + /* Nothing to do */ + break; + default: + Assert(0); + } + + /* Report error if necessary */ + if (err < 0 && event != GTM_EVENT_ABORT) + ereport(ERROR, + (errcode(ERRCODE_CONNECTION_FAILURE), + errmsg("GTM error, could not rename sequence"))); +} + + +/* * Register a callback for a sequence drop on GTM */ void diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index e542f51247..02042e6eb0 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -2311,6 +2311,9 @@ RenameRelation(Oid myrelid, const char *newrelname, ObjectType reltype) (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("GTM error, could not rename sequence"))); + /* Register a rename callback in case transaction is dropped */ + register_sequence_rename_cb(seqname, newseqname); + pfree(seqname); pfree(newseqname); } @@ -9126,6 +9129,9 @@ AlterTableNamespace(RangeVar *relation, const char *newschema, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("GTM error, could not rename sequence"))); + /* Register a rename callback in case transaction is dropped */ + register_sequence_rename_cb(seqname, newseqname); + pfree(seqname); pfree(newseqname); } @@ -9297,6 +9303,9 @@ AlterSeqNamespaces(Relation classRel, Relation rel, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("GTM error, could not rename sequence"))); + /* Register a rename callback in case transaction is dropped */ + register_sequence_rename_cb(seqname, newseqname); + pfree(seqname); pfree(newseqname); } diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index 84df50e101..f9d45de4af 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -87,7 +87,8 @@ extern void seq_desc(StringInfo buf, uint8 xl_info, char *rec); /* * List of actions that registered the callback. * This is listed here and not in sequence.c because callback can also - * be registered in dependency.c as sequences can be dropped in cascade. + * be registered in dependency.c and tablecmds.c as sequences can be dropped + * or renamed in cascade. */ typedef enum { @@ -96,6 +97,8 @@ typedef enum } GTM_SequenceDropType; /* Sequence callbacks on GTM */ +extern void register_sequence_rename_cb(char *oldseqname, char *newseqname); +extern void rename_sequence_cb(GTMEvent event, void *args); extern void register_sequence_cb(char *seqname, GTM_SequenceKeyType key, GTM_SequenceDropType type); extern void drop_sequence_cb(GTMEvent event, void *args); diff --git a/src/test/regress/expected/xc_sequence.out b/src/test/regress/expected/xc_sequence.out new file mode 100644 index 0000000000..6927847757 --- /dev/null +++ b/src/test/regress/expected/xc_sequence.out @@ -0,0 +1,178 @@ +-- +-- XC_SEQUENCE +-- +-- Check of callback mechanisms on GTM +-- Sequence DROP and CREATE +-- Rollback a creation +BEGIN; +CREATE SEQUENCE xc_sequence_1; +SELECT nextval('xc_sequence_1'); -- ok + nextval +--------- + 1 +(1 row) + +ROLLBACK; +SELECT nextval('xc_sequence_1'); -- fail +ERROR: relation "xc_sequence_1" does not exist +LINE 1: SELECT nextval('xc_sequence_1'); + ^ +-- Commit a creation +BEGIN; +CREATE SEQUENCE xc_sequence_1; +SELECT nextval('xc_sequence_1'); -- ok + nextval +--------- + 1 +(1 row) + +COMMIT; +SELECT nextval('xc_sequence_1'); -- ok + nextval +--------- + 2 +(1 row) + +-- Rollback a drop +BEGIN; +DROP SEQUENCE xc_sequence_1; +SELECT nextval('xc_sequence_1'); -- fail +ERROR: relation "xc_sequence_1" does not exist +LINE 1: SELECT nextval('xc_sequence_1'); + ^ +ROLLBACK; +SELECT nextval('xc_sequence_1'); -- ok, previous transaction failed + nextval +--------- + 3 +(1 row) + +-- Commit a drop +BEGIN; +DROP SEQUENCE xc_sequence_1; +COMMIT; +SELECT nextval('xc_sequence_1'); -- fail +ERROR: relation "xc_sequence_1" does not exist +LINE 1: SELECT nextval('xc_sequence_1'); + ^ +-- SEQUENCE RENAME TO +-- Rollback a renaming +CREATE SEQUENCE xc_sequence_1; +SELECT nextval('xc_sequence_1'); -- ok + nextval +--------- + 1 +(1 row) + +BEGIN; +ALTER SEQUENCE xc_sequence_1 RENAME TO xc_sequence_2; +SELECT nextval('xc_sequence_2'); -- ok + nextval +--------- + 2 +(1 row) + +ROLLBACK; +SELECT nextval('xc_sequence_1'); -- ok + nextval +--------- + 3 +(1 row) + +-- Commit a renaming +BEGIN; +ALTER SEQUENCE xc_sequence_1 RENAME TO xc_sequence_2; +SELECT nextval('xc_sequence_2'); -- ok + nextval +--------- + 4 +(1 row) + +COMMIT; +SELECT nextval('xc_sequence_2'); -- ok + nextval +--------- + 5 +(1 row) + +DROP SEQUENCE xc_sequence_2; +-- Columns with SERIAL +-- Serial sequence is named xc_sequence_tab1_col2_seq +CREATE TABLE xc_sequence_tab1 (col1 int, col2 serial) DISTRIBUTE BY ROUND ROBIN; +NOTICE: CREATE TABLE will create implicit sequence "xc_sequence_tab1_col2_seq" for serial column "xc_sequence_tab1.col2" +-- Some data +INSERT INTO xc_sequence_tab1 VALUES (1, DEFAULT); +INSERT INTO xc_sequence_tab1 VALUES (2, DEFAULT); +SELECT col1, col2 FROM xc_sequence_tab1 ORDER BY 1; + col1 | col2 +------+------ + 1 | 1 + 2 | 2 +(2 rows) + +-- Rollback a SERIAL column drop +BEGIN; +ALTER TABLE xc_sequence_tab1 DROP COLUMN col2; +INSERT INTO xc_sequence_tab1 VALUES (3); +SELECT col1 FROM xc_sequence_tab1 ORDER BY 1; + col1 +------ + 1 + 2 + 3 +(3 rows) + +ROLLBACK; +SELECT nextval('xc_sequence_tab1_col2_seq'); -- ok + nextval +--------- + 3 +(1 row) + +-- Commit a SERIAL column drop +BEGIN; +ALTER TABLE xc_sequence_tab1 DROP COLUMN col2; +INSERT INTO xc_sequence_tab1 VALUES (3); +SELECT col1 FROM xc_sequence_tab1 ORDER BY 1; + col1 +------ + 1 + 2 + 3 +(3 rows) + +COMMIT; +DROP TABLE xc_sequence_tab1; +-- Need to recreate here, serial column is no more +CREATE TABLE xc_sequence_tab1 (col1 int, col2 serial) DISTRIBUTE BY ROUND ROBIN; +NOTICE: CREATE TABLE will create implicit sequence "xc_sequence_tab1_col2_seq" for serial column "xc_sequence_tab1.col2" +INSERT INTO xc_sequence_tab1 VALUES (1234, DEFAULT); +SELECT col1, col2 FROM xc_sequence_tab1 ORDER BY 1; + col1 | col2 +------+------ + 1234 | 1 +(1 row) + +-- Rollback of a table with SERIAL +BEGIN; +DROP TABLE xc_sequence_tab1; +ROLLBACK; +SELECT nextval('xc_sequence_tab1_col2_seq'); -- ok + nextval +--------- + 2 +(1 row) + +-- Commit of a table with SERIAL +BEGIN; +DROP TABLE xc_sequence_tab1; +COMMIT; +-- Recreate a sequence with the same name as previous SERIAL one +CREATE SEQUENCE xc_sequence_tab1_col2_seq START 2344; +SELECT nextval('xc_sequence_tab1_col2_seq'); -- ok + nextval +--------- + 2344 +(1 row) + +DROP SEQUENCE xc_sequence_tab1_col2_seq; diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 8b3f496250..835d483f7f 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -104,7 +104,7 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid c test: stats #Postgres-XC additional tests, they can be run in parallel -test: xc_groupby xc_distkey xc_having xc_temp xc_remote xc_FQS xc_FQS_join xc_copy xc_for_update xc_alter_table +test: xc_groupby xc_distkey xc_having xc_temp xc_remote xc_FQS xc_FQS_join xc_copy xc_for_update xc_alter_table xc_sequence #Cluster setting related test is independant test: xc_node diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index fe4149ff81..8b4d7f9290 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -139,3 +139,4 @@ test: xc_misc test: xc_copy test: xc_for_update test: xc_alter_table +test: xc_sequence diff --git a/src/test/regress/sql/xc_sequence.sql b/src/test/regress/sql/xc_sequence.sql new file mode 100644 index 0000000000..0c731df967 --- /dev/null +++ b/src/test/regress/sql/xc_sequence.sql @@ -0,0 +1,86 @@ +-- +-- XC_SEQUENCE +-- + +-- Check of callback mechanisms on GTM + +-- Sequence DROP and CREATE +-- Rollback a creation +BEGIN; +CREATE SEQUENCE xc_sequence_1; +SELECT nextval('xc_sequence_1'); -- ok +ROLLBACK; +SELECT nextval('xc_sequence_1'); -- fail +-- Commit a creation +BEGIN; +CREATE SEQUENCE xc_sequence_1; +SELECT nextval('xc_sequence_1'); -- ok +COMMIT; +SELECT nextval('xc_sequence_1'); -- ok +-- Rollback a drop +BEGIN; +DROP SEQUENCE xc_sequence_1; +SELECT nextval('xc_sequence_1'); -- fail +ROLLBACK; +SELECT nextval('xc_sequence_1'); -- ok, previous transaction failed +-- Commit a drop +BEGIN; +DROP SEQUENCE xc_sequence_1; +COMMIT; +SELECT nextval('xc_sequence_1'); -- fail + +-- SEQUENCE RENAME TO +-- Rollback a renaming +CREATE SEQUENCE xc_sequence_1; +SELECT nextval('xc_sequence_1'); -- ok +BEGIN; +ALTER SEQUENCE xc_sequence_1 RENAME TO xc_sequence_2; +SELECT nextval('xc_sequence_2'); -- ok +ROLLBACK; +SELECT nextval('xc_sequence_1'); -- ok +-- Commit a renaming +BEGIN; +ALTER SEQUENCE xc_sequence_1 RENAME TO xc_sequence_2; +SELECT nextval('xc_sequence_2'); -- ok +COMMIT; +SELECT nextval('xc_sequence_2'); -- ok +DROP SEQUENCE xc_sequence_2; + +-- Columns with SERIAL +-- Serial sequence is named xc_sequence_tab1_col2_seq +CREATE TABLE xc_sequence_tab1 (col1 int, col2 serial) DISTRIBUTE BY ROUND ROBIN; +-- Some data +INSERT INTO xc_sequence_tab1 VALUES (1, DEFAULT); +INSERT INTO xc_sequence_tab1 VALUES (2, DEFAULT); +SELECT col1, col2 FROM xc_sequence_tab1 ORDER BY 1; +-- Rollback a SERIAL column drop +BEGIN; +ALTER TABLE xc_sequence_tab1 DROP COLUMN col2; +INSERT INTO xc_sequence_tab1 VALUES (3); +SELECT col1 FROM xc_sequence_tab1 ORDER BY 1; +ROLLBACK; +SELECT nextval('xc_sequence_tab1_col2_seq'); -- ok +-- Commit a SERIAL column drop +BEGIN; +ALTER TABLE xc_sequence_tab1 DROP COLUMN col2; +INSERT INTO xc_sequence_tab1 VALUES (3); +SELECT col1 FROM xc_sequence_tab1 ORDER BY 1; +COMMIT; +DROP TABLE xc_sequence_tab1; +-- Need to recreate here, serial column is no more +CREATE TABLE xc_sequence_tab1 (col1 int, col2 serial) DISTRIBUTE BY ROUND ROBIN; +INSERT INTO xc_sequence_tab1 VALUES (1234, DEFAULT); +SELECT col1, col2 FROM xc_sequence_tab1 ORDER BY 1; +-- Rollback of a table with SERIAL +BEGIN; +DROP TABLE xc_sequence_tab1; +ROLLBACK; +SELECT nextval('xc_sequence_tab1_col2_seq'); -- ok +-- Commit of a table with SERIAL +BEGIN; +DROP TABLE xc_sequence_tab1; +COMMIT; +-- Recreate a sequence with the same name as previous SERIAL one +CREATE SEQUENCE xc_sequence_tab1_col2_seq START 2344; +SELECT nextval('xc_sequence_tab1_col2_seq'); -- ok +DROP SEQUENCE xc_sequence_tab1_col2_seq; |