diff --git a/src/backend/distributed/commands/table.c b/src/backend/distributed/commands/table.c index 5f24dcacc..e38e1af53 100644 --- a/src/backend/distributed/commands/table.c +++ b/src/backend/distributed/commands/table.c @@ -702,12 +702,87 @@ PostprocessAlterTableSchemaStmt(Node *node, const char *queryString) /* - * SwitchToSequentialAndLocalExecutionIfPrimaryKeyNameTooLong generates the longest primary key name + * GenerateConstraintName creates and returns a default name for the constraints Citus supports + * for default naming. See ConstTypeCitusCanDefaultName function for the supported constraint types. + */ +static char * +GenerateConstraintName(const char *tabname, Oid namespaceId, Constraint *constraint) +{ + char *conname = NULL; + + switch (constraint->contype) + { + case CONSTR_PRIMARY: + { + conname = ChooseIndexName(tabname, namespaceId, + NULL, NULL, true, true); + break; + } + + case CONSTR_UNIQUE: + { + ListCell *lc; + List *indexParams = NIL; + + foreach(lc, constraint->keys) + { + IndexElem *iparam = makeNode(IndexElem); + iparam->name = pstrdup(strVal(lfirst(lc))); + indexParams = lappend(indexParams, iparam); + } + + conname = ChooseIndexName(tabname, namespaceId, + ChooseIndexColumnNames(indexParams), + NULL, false, true); + break; + } + + case CONSTR_EXCLUSION: + { + ListCell *lc; + List *indexParams = NIL; + List *excludeOpNames = NIL; + + foreach(lc, constraint->exclusions) + { + List *pair = (List *) lfirst(lc); + + Assert(list_length(pair) == 2); + IndexElem *elem = linitial_node(IndexElem, pair); + List *opname = lsecond_node(List, pair); + + indexParams = lappend(indexParams, elem); + excludeOpNames = lappend(excludeOpNames, opname); + } + + conname = ChooseIndexName(tabname, namespaceId, + ChooseIndexColumnNames(indexParams), + excludeOpNames, + false, true); + break; + } + + default: + { + ereport(ERROR, (errmsg( + "unsupported constraint type for generating a constraint name: %d", + constraint->contype))); + break; + } + } + + return conname; +} + + +/* + * SwitchToSequentialAndLocalExecutionIfConstraintNameTooLong generates the longest index constraint name * among the shards of the partitions, and if exceeds the limit switches to sequential and * local execution to prevent self-deadlocks. */ static void -SwitchToSequentialAndLocalExecutionIfPrimaryKeyNameTooLong(Oid relationId) +SwitchToSequentialAndLocalExecutionIfConstraintNameTooLong(Oid relationId, + Constraint *constraint) { if (!PartitionedTable(relationId)) { @@ -743,12 +818,10 @@ SwitchToSequentialAndLocalExecutionIfPrimaryKeyNameTooLong(Oid relationId) Oid namespaceOid = RelationGetNamespace(rel); RelationClose(rel); - char *primaryKeyName = ChooseIndexName(longestPartitionShardName, - namespaceOid, - NULL, NULL, true, true); + char *longestConname = GenerateConstraintName(longestPartitionShardName, + namespaceOid, constraint); - - if (primaryKeyName && strnlen(primaryKeyName, NAMEDATALEN) >= NAMEDATALEN - 1) + if (longestConname && strnlen(longestConname, NAMEDATALEN) >= NAMEDATALEN - 1) { if (ParallelQueryExecutedInTransaction()) { @@ -758,18 +831,18 @@ SwitchToSequentialAndLocalExecutionIfPrimaryKeyNameTooLong(Oid relationId) * thus contradicting our purpose of using sequential mode. */ ereport(ERROR, (errmsg( - "The primary key name (%s) on a shard is too long and could lead " + "The constraint name (%s) on a shard is too long and could lead " "to deadlocks when executed in a transaction " - "block after a parallel query", primaryKeyName), + "block after a parallel query", longestConname), errhint("Try re-running the transaction with " "\"SET LOCAL citus.multi_shard_modify_mode TO " "\'sequential\';\""))); } else { - elog(DEBUG1, "the primary key name on the shards of the partition " + elog(DEBUG1, "the constraint name on the shards of the partition " "is too long, switching to sequential and local execution " - "mode to prevent self deadlocks: %s", primaryKeyName); + "mode to prevent self deadlocks: %s", longestConname); SetLocalMultiShardModifyModeToSequential(); SetLocalExecutionStatus(LOCAL_EXECUTION_REQUIRED); @@ -779,39 +852,39 @@ SwitchToSequentialAndLocalExecutionIfPrimaryKeyNameTooLong(Oid relationId) /* - * PreprocessAlterTableAddPrimaryKey creates a new primary key constraint name changing the original alterTableCommand run by the utility hook. - * Then converts the ALTER TABLE ... ADD PRIMARY KEY ... command - * into ALTER TABLE ... ADD CONSTRAINT PRIMARY KEY format and returns the DDLJob + * PreprocessAlterTableAddIndexConstraint creates a new constraint name for the index constraints {PRIMARY KEY, UNIQUE, EXCLUDE} + * and changes the original alterTableCommand run by the utility hook to use the new constraint name. + * Then converts the ALTER TABLE ... ADD {PRIMARY KEY, UNIQUE, EXCLUDE} ... command + * into ALTER TABLE ... ADD CONSTRAINT {PRIMARY KEY, UNIQUE, EXCLUDE} format and returns the DDLJob * to run this command in the workers. */ static List * -PreprocessAlterTableAddPrimaryKey(AlterTableStmt *alterTableStatement, Oid relationId, - Constraint *constraint) +PreprocessAlterTableAddIndexConstraint(AlterTableStmt *alterTableStatement, Oid + relationId, + Constraint *constraint) { - /* We should only preprocess an ADD PRIMARY KEY command if we are changing the it. - * This only happens when we have to create a primary key name ourselves in the case that the client does + /* We should only preprocess an ADD CONSTRAINT command if we are changing the it. + * This only happens when we have to create a constraint name in citus since the client does * not specify a name. */ Assert(constraint->conname == NULL); - bool primary = true; - bool isconstraint = true; - Relation rel = RelationIdGetRelation(relationId); /* * Change the alterTableCommand so that the standard utility * hook runs it with the name we created. */ - constraint->conname = ChooseIndexName(RelationGetRelationName(rel), - RelationGetNamespace(rel), - NULL, NULL, primary, - isconstraint); + + constraint->conname = GenerateConstraintName(RelationGetRelationName(rel), + RelationGetNamespace(rel), + constraint); + RelationClose(rel); - char *ddlCommand = DeparseTreeNode((Node *) alterTableStatement); + SwitchToSequentialAndLocalExecutionIfConstraintNameTooLong(relationId, constraint); - SwitchToSequentialAndLocalExecutionIfPrimaryKeyNameTooLong(relationId); + char *ddlCommand = DeparseTreeNode((Node *) alterTableStatement); DDLJob *ddlJob = palloc0(sizeof(DDLJob)); @@ -1063,17 +1136,18 @@ PreprocessAlterTableStmt(Node *node, const char *alterTableCommand, */ constraint->skip_validation = true; } - else if (constraint->contype == CONSTR_PRIMARY) + else if (constraint->conname == NULL) { - if (constraint->conname == NULL) + if (ConstrTypeCitusCanDefaultName(constraint->contype)) { /* * Create a constraint name. Convert ALTER TABLE ... ADD PRIMARY ... command into * ALTER TABLE ... ADD CONSTRAINT PRIMARY KEY ... form and create the ddl jobs * for running this form of the command on the workers. */ - return PreprocessAlterTableAddPrimaryKey(alterTableStatement, - leftRelationId, constraint); + return PreprocessAlterTableAddIndexConstraint(alterTableStatement, + leftRelationId, + constraint); } } } @@ -1824,6 +1898,18 @@ ConstrTypeUsesIndex(ConstrType constrType) } +/* + * ConstrTypeSupportsDefaultNaming returns true if we can generate a default name for the given constraint type + */ +bool +ConstrTypeCitusCanDefaultName(ConstrType constrType) +{ + return constrType == CONSTR_PRIMARY || + constrType == CONSTR_UNIQUE || + constrType == CONSTR_EXCLUSION; +} + + /* * AlterTableDropsForeignKey returns true if the given AlterTableStmt drops * a foreign key. False otherwise. @@ -3025,7 +3111,7 @@ ErrorIfUnsupportedAlterTableStmt(AlterTableStmt *alterTableStatement) * and changing the command into the following form. * ALTER TABLE ... ADD CONSTRAINT PRIMARY KEY ... */ - if (constraint->contype != CONSTR_PRIMARY) + if (ConstrTypeCitusCanDefaultName(constraint->contype) == false) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg( diff --git a/src/backend/distributed/deparser/deparse_table_stmts.c b/src/backend/distributed/deparser/deparse_table_stmts.c index dd6b665f6..c4cb7d4c2 100644 --- a/src/backend/distributed/deparser/deparse_table_stmts.c +++ b/src/backend/distributed/deparser/deparse_table_stmts.c @@ -11,6 +11,7 @@ */ #include "postgres.h" +#include "distributed/commands.h" #include "distributed/deparser.h" #include "distributed/version_compat.h" #include "nodes/nodes.h" @@ -103,10 +104,138 @@ AppendAlterTableStmt(StringInfo buf, AlterTableStmt *stmt) } +/* + * AppendAlterTableCmdAddConstraint builds the add constraint command for index constraints + * in the ADD CONSTRAINT {PRIMARY KEY, UNIQUE, EXCLUSION} form and appends it to the buf. + */ +static void +AppendAlterTableCmdAddConstraint(StringInfo buf, Constraint *constraint) +{ + /* Need to deparse the alter table constraint command only if we are adding a constraint name.*/ + if (constraint->conname == NULL) + { + ereport(ERROR, (errmsg( + "Constraint name can not be NULL when deparsing the constraint."))); + } + + appendStringInfoString(buf, " ADD CONSTRAINT "); + appendStringInfo(buf, "%s ", quote_identifier(constraint->conname)); + + /* postgres version >= PG15 + * UNIQUE [ NULLS [ NOT ] DISTINCT ] ( column_name [, ... ] ) [ INCLUDE ( column_name [, ...]) ] + * postgres version < PG15 + * UNIQUE ( column_name [, ... ] ) [ INCLUDE ( column_name [, ...]) ] + * PRIMARY KEY ( column_name [, ... ] ) [ INCLUDE ( column_name [, ...]) ] + */ + if (constraint->contype == CONSTR_PRIMARY || constraint->contype == CONSTR_UNIQUE) + { + if (constraint->contype == CONSTR_PRIMARY) + { + appendStringInfoString(buf, + " PRIMARY KEY ("); + } + else + { + appendStringInfoString(buf, " UNIQUE"); + +#if (PG_VERSION_NUM >= PG_VERSION_15) + if (constraint->nulls_not_distinct == true) + { + appendStringInfoString(buf, " NULLS NOT DISTINCT"); + } +#endif + appendStringInfoString(buf, " ("); + } + + ListCell *lc; + bool firstkey = true; + + foreach(lc, constraint->keys) + { + if (firstkey == false) + { + appendStringInfoString(buf, ", "); + } + + appendStringInfo(buf, "%s", quote_identifier(strVal(lfirst(lc)))); + firstkey = false; + } + + appendStringInfoString(buf, ")"); + + if (constraint->including != NULL) + { + appendStringInfoString(buf, " INCLUDE ("); + + firstkey = true; + + foreach(lc, constraint->including) + { + if (firstkey == false) + { + appendStringInfoString(buf, ", "); + } + + appendStringInfo(buf, "%s", quote_identifier(strVal(lfirst( + lc)))); + firstkey = false; + } + + appendStringInfoString(buf, " )"); + } + } + else if (constraint->contype == CONSTR_EXCLUSION) + { + /* + * This block constructs the EXCLUDE clause which is in the following form: + * EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) + */ + appendStringInfoString(buf, " EXCLUDE "); + + if (constraint->access_method != NULL) + { + appendStringInfoString(buf, "USING "); + appendStringInfo(buf, "%s ", quote_identifier( + constraint->access_method)); + } + + appendStringInfoString(buf, " ("); + + ListCell *lc; + bool firstOp = true; + + foreach(lc, constraint->exclusions) + { + List *pair = (List *) lfirst(lc); + + Assert(list_length(pair) == 2); + IndexElem *elem = linitial_node(IndexElem, pair); + List *opname = lsecond_node(List, pair); + if (firstOp == false) + { + appendStringInfoString(buf, " ,"); + } + + ListCell *lc2; + + foreach(lc2, opname) + { + appendStringInfo(buf, "%s WITH %s", quote_identifier(elem->name), + strVal(lfirst(lc2))); + } + + firstOp = false; + } + + appendStringInfoString(buf, " )"); + } +} + + /* * AppendAlterTableCmd builds and appends to the given buffer a command * from given AlterTableCmd object. Currently supported commands are of type - * AT_AddColumn and AT_SetNotNull + * AT_AddColumn, AT_SetNotNull and AT_AddConstraint {PRIMARY KEY, UNIQUE, EXCLUDE}. */ static void AppendAlterTableCmd(StringInfo buf, AlterTableCmd *alterTableCmd) @@ -123,38 +252,13 @@ AppendAlterTableCmd(StringInfo buf, AlterTableCmd *alterTableCmd) { Constraint *constraint = (Constraint *) alterTableCmd->def; - /* We need to deparse ALTER TABLE ... PRIMARY KEY commands into - * ALTER TABLE ... ADD CONSTRAINT PRIMARY KEY ... to be able + /* We need to deparse ALTER TABLE ... ADD {PRIMARY KEY, UNIQUE, EXCLUSION} commands into + * ALTER TABLE ... ADD CONSTRAINT {PRIMARY KEY, UNIQUE, EXCLUSION} ... format to be able * add a constraint name. */ - if (constraint->contype == CONSTR_PRIMARY) + if (ConstrTypeCitusCanDefaultName(constraint->contype)) { - /* Need to deparse PRIMARY KEY constraint commands only if adding a name.*/ - if (constraint->conname == NULL) - { - ereport(ERROR, (errmsg( - "Constraint name can not be NULL when constraint type is PRIMARY KEY"))); - } - - appendStringInfoString(buf, " ADD CONSTRAINT "); - appendStringInfo(buf, "%s ", quote_identifier(constraint->conname)); - appendStringInfoString(buf, " PRIMARY KEY ("); - - ListCell *lc; - bool firstkey = true; - - foreach(lc, constraint->keys) - { - if (firstkey == false) - { - appendStringInfoString(buf, ", "); - } - - appendStringInfo(buf, "%s", quote_identifier(strVal(lfirst(lc)))); - firstkey = false; - } - - appendStringInfoString(buf, ")"); + AppendAlterTableCmdAddConstraint(buf, constraint); break; } } diff --git a/src/include/distributed/commands.h b/src/include/distributed/commands.h index fa2691fee..add0937ec 100644 --- a/src/include/distributed/commands.h +++ b/src/include/distributed/commands.h @@ -561,6 +561,7 @@ extern List * AlterTableSchemaStmtObjectAddress(Node *stmt, extern List * MakeNameListFromRangeVar(const RangeVar *rel); extern Oid GetSequenceOid(Oid relationId, AttrNumber attnum); extern bool ConstrTypeUsesIndex(ConstrType constrType); +extern bool ConstrTypeCitusCanDefaultName(ConstrType constrType); /* text_search.c - forward declarations */ diff --git a/src/test/regress/expected/multi_alter_table_add_constraints.out b/src/test/regress/expected/multi_alter_table_add_constraints.out index 83d2de7f8..c9d9103ce 100644 --- a/src/test/regress/expected/multi_alter_table_add_constraints.out +++ b/src/test/regress/expected/multi_alter_table_add_constraints.out @@ -434,13 +434,8 @@ ERROR: cannot execute ADD CONSTRAINT command with other subcommands HINT: You can issue each subcommand separately -- Tests for constraints without name -- Commands below should error out since constraints do not have the name -ALTER TABLE products ADD UNIQUE(product_no); -ERROR: cannot create constraint without a name on a distributed table -ALTER TABLE products ADD PRIMARY KEY(product_no); ALTER TABLE products ADD CHECK(product_no <> 0); ERROR: cannot create constraint without a name on a distributed table -ALTER TABLE products ADD EXCLUDE USING btree (product_no with =); -ERROR: cannot create constraint without a name on a distributed table -- ... with names, we can add/drop the constraints just fine ALTER TABLE products ADD CONSTRAINT nonzero_product_no CHECK(product_no <> 0); ALTER TABLE products ADD CONSTRAINT uniq_product_no EXCLUDE USING btree (product_no with =); @@ -689,6 +684,8 @@ DROP SCHEMA sc3 CASCADE; NOTICE: drop cascades to 2 other objects DETAIL: drop cascades to table sc3.alter_add_prim_key drop cascades to table sc3.alter_add_unique +CREATE SCHEMA test_auto_explain; +SET search_path TO 'test_auto_explain'; -- Test ALTER TABLE ... ADD CONSTRAINT ... does not cause a crash when auto_explain module is loaded CREATE TABLE target_table(col_1 int primary key, col_2 int); SELECT create_distributed_table('target_table','col_1'); @@ -720,7 +717,7 @@ SET citus.enable_ddl_propagation TO OFF; ALTER TABLE target_table ADD CONSTRAINT fkey_167 FOREIGN KEY (col_1) REFERENCES test_ref_table(key) ON DELETE CASCADE; LOG: duration: xxxx ms plan: { - "Query Text": "SELECT fk.\"col_1\" FROM ONLY \"public\".\"target_table\" fk LEFT OUTER JOIN ONLY \"public\".\"test_ref_table\" pk ON ( pk.\"key\" OPERATOR(pg_catalog.=) fk.\"col_1\") WHERE pk.\"key\" IS NULL AND (fk.\"col_1\" IS NOT NULL)", + "Query Text": "SELECT fk.\"col_1\" FROM ONLY \"test_auto_explain\".\"target_table\" fk LEFT OUTER JOIN ONLY \"test_auto_explain\".\"test_ref_table\" pk ON ( pk.\"key\" OPERATOR(pg_catalog.=) fk.\"col_1\") WHERE pk.\"key\" IS NULL AND (fk.\"col_1\" IS NOT NULL)", "Plan": { "Node Type": "Custom Scan", "Custom Plan Provider": "Citus Adaptive", @@ -732,5 +729,9 @@ LOG: duration: xxxx ms plan: "Citus Explain Scan": "Explain for triggered constraint validation queries during ALTER TABLE commands are not supported by Citus" } } -CONTEXT: SQL statement "SELECT fk."col_1" FROM ONLY "public"."target_table" fk LEFT OUTER JOIN ONLY "public"."test_ref_table" pk ON ( pk."key" OPERATOR(pg_catalog.=) fk."col_1") WHERE pk."key" IS NULL AND (fk."col_1" IS NOT NULL)" +CONTEXT: SQL statement "SELECT fk."col_1" FROM ONLY "test_auto_explain"."target_table" fk LEFT OUTER JOIN ONLY "test_auto_explain"."test_ref_table" pk ON ( pk."key" OPERATOR(pg_catalog.=) fk."col_1") WHERE pk."key" IS NULL AND (fk."col_1" IS NOT NULL)" END; +RESET citus.enable_ddl_propagation; +SET client_min_messages to ERROR; +SET search_path TO 'public'; +DROP SCHEMA test_auto_explain CASCADE; diff --git a/src/test/regress/expected/multi_alter_table_add_constraints_without_name.out b/src/test/regress/expected/multi_alter_table_add_constraints_without_name.out index 9e76a8255..d0602b5a7 100644 --- a/src/test/regress/expected/multi_alter_table_add_constraints_without_name.out +++ b/src/test/regress/expected/multi_alter_table_add_constraints_without_name.out @@ -30,7 +30,7 @@ SELECT con.conname (1 row) -- Check that the primary key name created on the coordinator is sent to workers and --- the constraints created for the shard tables conform to the _shardid scheme. +-- the constraints created for the shard tables conform to the _shardid naming scheme. \c - - :public_worker_1_host :worker_1_port SELECT con.conname FROM pg_catalog.pg_constraint con @@ -44,7 +44,117 @@ SELECT con.conname \c - - :master_host :master_port ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_pkey; -ALTER TABLE AT_AddConstNoName.products ADD PRIMARY KEY(product_no); +-- Check "ADD UNIQUE" +ALTER TABLE AT_AddConstNoName.products ADD UNIQUE(product_no); +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products'; + conname +--------------------------------------------------------------------- + products_product_no_key +(1 row) + +-- Check that UNIQUE constraint name created on the coordinator is sent to workers and +-- the constraints created for the shard tables conform to the _shardid scheme. +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_5410000'; + conname +--------------------------------------------------------------------- + products_product_no_key_5410000 +(1 row) + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_key; +-- Check "ADD UNIQUE" with column name list +ALTER TABLE AT_AddConstNoName.products ADD UNIQUE(product_no,name); +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products'; + conname +--------------------------------------------------------------------- + products_product_no_name_key +(1 row) + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_5410000'; + conname +--------------------------------------------------------------------- + products_product_no_name_key_5410000 +(1 row) + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_name_key; +-- Check "ADD UNIQUE ... INCLUDE" +ALTER TABLE AT_AddConstNoName.products ADD UNIQUE(product_no) INCLUDE(price); +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products'; + conname +--------------------------------------------------------------------- + products_product_no_key +(1 row) + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_5410000'; + conname +--------------------------------------------------------------------- + products_product_no_key_5410000 +(1 row) + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_key; +-- Check "ADD UNIQUE NULLS NOT DISTICT" +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 +\gset +\if :server_version_ge_15 +ALTER TABLE AT_AddConstNoName.products ADD UNIQUE NULLS NOT DISTINCT (product_no, price); +ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_price_key; +\endif +-- Check "ADD EXCLUDE" +CREATE EXTENSION btree_gist; +ALTER TABLE AT_AddConstNoName.products ADD EXCLUDE USING gist (name WITH <> , product_no WITH =); +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products'; + conname +--------------------------------------------------------------------- + products_name_product_no_excl +(1 row) + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_5410000'; + conname +--------------------------------------------------------------------- + products_name_product_no_excl_5410000 +(1 row) + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_name_product_no_excl; DROP TABLE AT_AddConstNoName.products; -- Check "ADD PRIMARY KEY" with reference table CREATE TABLE AT_AddConstNoName.products_ref ( @@ -74,7 +184,7 @@ SELECT create_reference_table('AT_AddConstNoName.products_ref_3'); (1 row) --- Check for name collisions +-- Check that name collisions are handled for PRIMARY KEY. ALTER TABLE AT_AddConstNoName.products_ref_3 ADD CONSTRAINT products_ref_pkey PRIMARY KEY(name); ALTER TABLE AT_AddConstNoName.products_ref_2 ADD CONSTRAINT products_ref_pkey1 PRIMARY KEY(name); ALTER TABLE AT_AddConstNoName.products_ref ADD PRIMARY KEY(name); @@ -89,8 +199,37 @@ SELECT con.conname (1 row) ALTER TABLE AT_AddConstNoName.products_ref DROP CONSTRAINT products_ref_pkey2; +-- Check that name collisions are handled for UNIQUE. +ALTER TABLE AT_AddConstNoName.products_ref_3 ADD CONSTRAINT products_ref_name_key UNIQUE(name); +ALTER TABLE AT_AddConstNoName.products_ref_2 ADD CONSTRAINT products_ref_name_key1 UNIQUE(name); +ALTER TABLE AT_AddConstNoName.products_ref ADD UNIQUE(name); +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_ref'; + conname +--------------------------------------------------------------------- + products_ref_name_key2 +(1 row) + +ALTER TABLE AT_AddConstNoName.products_ref DROP CONSTRAINT products_ref_name_key2; +-- Check that name collisions are handled for EXCLUDE +ALTER TABLE AT_AddConstNoName.products_ref_3 ADD CONSTRAINT products_ref_product_no_excl EXCLUDE (product_no WITH =); +ALTER TABLE AT_AddConstNoName.products_ref_2 ADD CONSTRAINT products_ref_product_no_excl1 EXCLUDE (product_no WITH =); +ALTER TABLE AT_AddConstNoName.products_ref ADD EXCLUDE(product_no WITH =); +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_ref'; + conname +--------------------------------------------------------------------- + products_ref_product_no_excl2 +(1 row) + DROP TABLE AT_AddConstNoName.products_ref; --- Check with max table name (63 chars) +-- Check "ADD PRIMARY KEY" with max table name (63 chars) CREATE TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonger ( product_no integer, name text, @@ -144,6 +283,92 @@ SELECT con.conname --------------------------------------------------------------------- (0 rows) +-- Check "ADD UNIQUE" with max table name (63 chars) +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon ADD UNIQUE(product_no); +-- Constraint should be created on the coordinator with a shortened name +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%'; + conname +--------------------------------------------------------------------- + verylonglonglonglonglonglonglonglonglonglonglong_product_no_key +(1 row) + +-- Constraints for the main table and the shards should be created on the worker with a shortened name +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- + verylonglonglonglonglonglonglonglonglonglonglo_cd61b0cf_5410006 + verylonglonglonglonglonglonglonglonglonglonglo_cd61b0cf_5410007 + verylonglonglonglonglonglonglonglonglonglonglo_cd61b0cf_5410008 + verylonglonglonglonglonglonglonglonglonglonglo_cd61b0cf_5410009 + verylonglonglonglonglonglonglonglonglonglonglong_product_no_key +(5 rows) + +-- UNIQUE constraint can be deleted via the coordinator +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon DROP CONSTRAINT verylonglonglonglonglonglonglonglonglonglonglong_product_no_key; +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%'; + conname +--------------------------------------------------------------------- +(0 rows) + +-- Check "ADD EXCLUDE" with max table name (63 chars) +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon ADD EXCLUDE (product_no WITH =); +-- Constraint should be created on the coordinator with a shortened name +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%'; + conname +--------------------------------------------------------------------- + verylonglonglonglonglonglonglonglonglonglonglon_product_no_excl +(1 row) + +-- Constraints for the main table and the shards should be created on the worker with a shortened name +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- + verylonglonglonglonglonglonglonglonglonglonglo_057ed027_5410006 + verylonglonglonglonglonglonglonglonglonglonglo_057ed027_5410007 + verylonglonglonglonglonglonglonglonglonglonglo_057ed027_5410008 + verylonglonglonglonglonglonglonglonglonglonglo_057ed027_5410009 + verylonglonglonglonglonglonglonglonglonglonglon_product_no_excl +(5 rows) + +-- EXCLUDE constraint can be deleted via the coordinator +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon DROP CONSTRAINT verylonglonglonglonglonglonglonglonglonglonglon_product_no_excl; +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%'; + conname +--------------------------------------------------------------------- +(0 rows) + -- Test the scenario where a partitioned distributed table has a child with max allowed name -- Verify that we switch to sequential execution mode to avoid deadlock in this scenario \c - - :master_host :master_port @@ -156,9 +381,10 @@ SELECT create_distributed_table('AT_AddConstNoName.dist_partitioned_table', 'par (1 row) +-- Check "ADD PRIMARY KEY" SET client_min_messages TO DEBUG1; ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD PRIMARY KEY(partition_col); -DEBUG: the primary key name on the shards of the partition is too long, switching to sequential and local execution mode to prevent self deadlocks: longlonglonglonglonglonglonglonglonglonglonglo_537570f5_54_pkey +DEBUG: the constraint name on the shards of the partition is too long, switching to sequential and local execution mode to prevent self deadlocks: longlonglonglonglonglonglonglonglonglonglonglo_537570f5_54_pkey DEBUG: ALTER TABLE / ADD PRIMARY KEY will create implicit index "dist_partitioned_table_pkey" for table "dist_partitioned_table" DEBUG: ALTER TABLE / ADD PRIMARY KEY will create implicit index "longlonglonglonglonglonglonglonglonglonglonglonglonglonglo_pkey" for table "longlonglonglonglonglonglonglonglonglonglonglonglonglonglongabc" DEBUG: ALTER TABLE / ADD PRIMARY KEY will create implicit index "p1_pkey" for table "p1" @@ -202,8 +428,55 @@ SELECT con.conname --------------------------------------------------------------------- (0 rows) --- Test we error out when creating a primary key on a partition table with a long name if we cannot +-- Check "ADD UNIQUE" +\c - - :master_host :master_port +SET client_min_messages TO DEBUG1; +ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD UNIQUE(partition_col); +DEBUG: the constraint name on the shards of the partition is too long, switching to sequential and local execution mode to prevent self deadlocks: longlonglonglonglonglonglonglonglonglonglongl_partition_col_key +DEBUG: ALTER TABLE / ADD UNIQUE will create implicit index "dist_partitioned_table_partition_col_key" for table "dist_partitioned_table" +DEBUG: ALTER TABLE / ADD UNIQUE will create implicit index "longlonglonglonglonglonglonglonglonglonglongl_partition_col_key" for table "longlonglonglonglonglonglonglonglonglonglonglonglonglonglongabc" +DEBUG: ALTER TABLE / ADD UNIQUE will create implicit index "p1_partition_col_key" for table "p1" +RESET client_min_messages; +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'dist_partitioned_table'; + conname +--------------------------------------------------------------------- + dist_partitioned_table_partition_col_key +(1 row) + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'longlonglonglonglonglonglonglonglong%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- + longlonglonglonglonglonglonglonglonglonglongl__d794d9f1_5410014 + longlonglonglonglonglonglonglonglonglonglongl__d794d9f1_5410015 + longlonglonglonglonglonglonglonglonglonglongl__d794d9f1_5410016 + longlonglonglonglonglonglonglonglonglonglongl__d794d9f1_5410017 + longlonglonglonglonglonglonglonglonglonglongl_partition_col_key +(5 rows) + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.dist_partitioned_table DROP CONSTRAINT dist_partitioned_table_partition_col_key; +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'longlonglonglonglonglonglonglonglong%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- +(0 rows) + +-- Test we error out when creating a constraint on a partition table with a long name if we cannot -- switch to sequential execution +-- Check "ADD PRIMARY KEY" \c - - :master_host :master_port BEGIN; SELECT count(*) FROM AT_AddConstNoName.dist_partitioned_table; @@ -213,7 +486,7 @@ BEGIN; (1 row) ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD PRIMARY KEY(partition_col); -ERROR: The primary key name (longlonglonglonglonglonglonglonglonglonglonglo_537570f5_54_pkey) on a shard is too long and could lead to deadlocks when executed in a transaction block after a parallel query +ERROR: The constraint name (longlonglonglonglonglonglonglonglonglonglonglo_537570f5_54_pkey) on a shard is too long and could lead to deadlocks when executed in a transaction block after a parallel query HINT: Try re-running the transaction with "SET LOCAL citus.multi_shard_modify_mode TO 'sequential';" ROLLBACK; -- try inside a sequential block @@ -227,8 +500,33 @@ BEGIN; ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD PRIMARY KEY(partition_col); ROLLBACK; +-- Check "ADD UNIQUE" +\c - - :master_host :master_port +BEGIN; + SELECT count(*) FROM AT_AddConstNoName.dist_partitioned_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + + ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD UNIQUE(partition_col); +ERROR: The constraint name (longlonglonglonglonglonglonglonglonglonglongl_partition_col_key) on a shard is too long and could lead to deadlocks when executed in a transaction block after a parallel query +HINT: Try re-running the transaction with "SET LOCAL citus.multi_shard_modify_mode TO 'sequential';" +ROLLBACK; +-- try inside a sequential block +BEGIN; + SET LOCAL citus.multi_shard_modify_mode TO 'sequential'; + SELECT count(*) FROM AT_AddConstNoName.dist_partitioned_table; + count +--------------------------------------------------------------------- + 0 +(1 row) + + ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD UNIQUE(partition_col); + ROLLBACK; DROP TABLE AT_AddConstNoName.dist_partitioned_table; --- Test primary key name is generated by postgres for citus local table. +-- Test with Citus Local Tables +-- Test "ADD PRIMARY KEY" \c - - :master_host :master_port SET client_min_messages to ERROR; SELECT 1 FROM master_add_node('localhost', :master_port, groupId => 0); @@ -246,7 +544,7 @@ SELECT citus_add_local_table_to_metadata('AT_AddConstNoName.citus_local_table'); (1 row) ALTER TABLE AT_AddConstNoName.citus_local_table ADD PRIMARY KEY(id); --- Check the primary key is created for the local table and its shard. +-- Check the primary key is created for the local table and its shard SELECT con.conname FROM pg_catalog.pg_constraint con INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid @@ -289,6 +587,78 @@ SELECT con.conname citus_local_table_pkey_5410026 (5 rows) +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.citus_local_table DROP CONSTRAINT citus_local_table_pkey; +-- Check "ADD UNIQUE" +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.citus_local_table ADD UNIQUE(id); +-- Check the UNIQUE constraint is created for the local table and its shard +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- + citus_local_table_id_key +(1 row) + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- + citus_local_table_id_key + citus_local_table_id_key_5410023 + citus_local_table_id_key_5410024 + citus_local_table_id_key_5410025 + citus_local_table_id_key_5410026 +(5 rows) + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.citus_local_table DROP CONSTRAINT citus_local_table_id_key; +-- Check "ADD EXCLUDE" +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.citus_local_table ADD EXCLUDE(id WITH =); +-- Check the EXCLUDE constraint is created for the local table and its shard +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- + citus_local_table_id_excl +(1 row) + +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- + citus_local_table_id_excl +(1 row) + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- + citus_local_table_id_excl + citus_local_table_id_excl_5410023 + citus_local_table_id_excl_5410024 + citus_local_table_id_excl_5410025 + citus_local_table_id_excl_5410026 +(5 rows) + \c - - :master_host :master_port DROP TABLE AT_AddConstNoName.citus_local_table; -- Test with partitioned citus local table @@ -301,6 +671,7 @@ SELECT citus_add_local_table_to_metadata('AT_AddConstNoName.citus_local_partitio (1 row) +-- Check "ADD PRIMARY KEY" ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD PRIMARY KEY(partition_col); SELECT create_distributed_table('AT_AddConstNoName.citus_local_partitioned_table', 'partition_col'); create_distributed_table @@ -311,7 +682,7 @@ SELECT create_distributed_table('AT_AddConstNoName.citus_local_partitioned_table ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table DROP CONSTRAINT citus_local_partitioned_table_pkey; SET client_min_messages TO DEBUG1; ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD PRIMARY KEY(partition_col); -DEBUG: the primary key name on the shards of the partition is too long, switching to sequential and local execution mode to prevent self deadlocks: longlonglonglonglonglonglonglonglonglonglonglo_537570f5_54_pkey +DEBUG: the constraint name on the shards of the partition is too long, switching to sequential and local execution mode to prevent self deadlocks: longlonglonglonglonglonglonglonglonglonglonglo_537570f5_54_pkey DEBUG: ALTER TABLE / ADD PRIMARY KEY will create implicit index "citus_local_partitioned_table_pkey" for table "citus_local_partitioned_table" DEBUG: ALTER TABLE / ADD PRIMARY KEY will create implicit index "longlonglonglonglonglonglonglonglonglonglonglonglonglonglo_pkey" for table "longlonglonglonglonglonglonglonglonglonglonglonglonglonglongabc" DEBUG: ALTER TABLE / ADD PRIMARY KEY will create implicit index "p1_pkey" for table "p1" @@ -343,6 +714,46 @@ SELECT con.conname \c - - :master_host :master_port ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table DROP CONSTRAINT citus_local_partitioned_table_pkey; +-- Check "ADD UNIQUE" +ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD UNIQUE(partition_col); +ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table DROP CONSTRAINT citus_local_partitioned_table_partition_col_key; +SET client_min_messages TO DEBUG1; +ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD UNIQUE(partition_col); +DEBUG: the constraint name on the shards of the partition is too long, switching to sequential and local execution mode to prevent self deadlocks: longlonglonglonglonglonglonglonglonglonglongl_partition_col_key +DEBUG: ALTER TABLE / ADD UNIQUE will create implicit index "citus_local_partitioned_table_partition_col_key" for table "citus_local_partitioned_table" +DEBUG: ALTER TABLE / ADD UNIQUE will create implicit index "longlonglonglonglonglonglonglonglonglonglongl_partition_col_key" for table "longlonglonglonglonglonglonglonglonglonglonglonglonglonglongabc" +DEBUG: ALTER TABLE / ADD UNIQUE will create implicit index "p1_partition_col_key" for table "p1" +RESET client_min_messages; +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'citus_local_partitioned_table'; + conname +--------------------------------------------------------------------- + citus_local_partitioned_table_partition_col_key +(1 row) + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'longlonglonglonglonglonglonglonglong%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- + longlonglonglonglonglonglonglonglonglonglongl__d794d9f1_5410034 + longlonglonglonglonglonglonglonglonglonglongl__d794d9f1_5410035 + longlonglonglonglonglonglonglonglonglonglongl__d794d9f1_5410036 + longlonglonglonglonglonglonglonglonglonglongl__d794d9f1_5410037 + longlonglonglonglonglonglonglonglonglonglongl_partition_col_key +(5 rows) + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table DROP CONSTRAINT citus_local_partitioned_table_partition_col_key; +-- Check "ADD EXCLUDE" errors out for partitioned table since the postgres does not allow it +ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD EXCLUDE(partition_col WITH =); +ERROR: exclusion constraints are not supported on partitioned tables SELECT 1 FROM master_remove_node('localhost', :master_port); ?column? --------------------------------------------------------------------- @@ -357,6 +768,7 @@ SELECT create_distributed_table('AT_AddConstNoName."2nd table"','2nd id'); (1 row) +-- Check "ADD PRIMARY KEY" ALTER TABLE AT_AddConstNoName."2nd table" ADD PRIMARY KEY ("2nd id", "3rd id"); SELECT con.conname FROM pg_catalog.pg_constraint con @@ -386,6 +798,67 @@ SELECT con.conname \c - - :master_host :master_port ALTER TABLE AT_AddConstNoName."2nd table" DROP CONSTRAINT "2nd table_pkey"; +-- Check "ADD UNIQUE" +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName."2nd table" ADD UNIQUE ("2nd id", "3rd id"); +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = '2nd table'; + conname +--------------------------------------------------------------------- + 2nd table_2nd id_3rd id_key +(1 row) + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE '2nd table%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- + 2nd table_2nd id_3rd id_key + 2nd table_2nd id_3rd id_key_5410042 + 2nd table_2nd id_3rd id_key_5410043 + 2nd table_2nd id_3rd id_key_5410044 + 2nd table_2nd id_3rd id_key_5410045 +(5 rows) + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName."2nd table" DROP CONSTRAINT "2nd table_2nd id_3rd id_key"; +-- Check "ADD EXCLUDE" +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName."2nd table" ADD EXCLUDE ("2nd id" WITH =); +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = '2nd table'; + conname +--------------------------------------------------------------------- + 2nd table_2nd id_excl +(1 row) + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE '2nd table%' ORDER BY con.conname ASC; + conname +--------------------------------------------------------------------- + 2nd table_2nd id_excl + 2nd table_2nd id_excl_5410042 + 2nd table_2nd id_excl_5410043 + 2nd table_2nd id_excl_5410044 + 2nd table_2nd id_excl_5410045 +(5 rows) + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName."2nd table" DROP CONSTRAINT "2nd table_2nd id_excl"; +DROP EXTENSION btree_gist; DROP SCHEMA AT_AddConstNoName CASCADE; NOTICE: drop cascades to 6 other objects DETAIL: drop cascades to table at_addconstnoname.products_ref_2 diff --git a/src/test/regress/expected/multi_name_lengths.out b/src/test/regress/expected/multi_name_lengths.out index 13825357f..32e483033 100644 --- a/src/test/regress/expected/multi_name_lengths.out +++ b/src/test/regress/expected/multi_name_lengths.out @@ -68,10 +68,6 @@ ALTER TABLE name_lengths ADD COLUMN float_col_1234567890123456789012345678901234 ALTER TABLE name_lengths ADD COLUMN date_col_12345678901234567890123456789012345678901234567890 DATE; ALTER TABLE name_lengths ADD COLUMN int_col_12345678901234567890123456789012345678901234567890 INTEGER DEFAULT 1; -- Placeholders for unsupported ALTER TABLE to add constraints with implicit names that are likely too long -ALTER TABLE name_lengths ADD UNIQUE (float_col_12345678901234567890123456789012345678901234567890); -ERROR: cannot create constraint without a name on a distributed table -ALTER TABLE name_lengths ADD EXCLUDE (int_col_12345678901234567890123456789012345678901234567890 WITH =); -ERROR: cannot create constraint without a name on a distributed table ALTER TABLE name_lengths ADD CHECK (date_col_12345678901234567890123456789012345678901234567890 > '2014-01-01'::date); ERROR: cannot create constraint without a name on a distributed table \c - - :public_worker_1_host :worker_1_port diff --git a/src/test/regress/sql/multi_alter_table_add_constraints.sql b/src/test/regress/sql/multi_alter_table_add_constraints.sql index ccfc18fb9..f553c9231 100644 --- a/src/test/regress/sql/multi_alter_table_add_constraints.sql +++ b/src/test/regress/sql/multi_alter_table_add_constraints.sql @@ -378,10 +378,7 @@ ALTER TABLE products ADD CONSTRAINT unn_1 UNIQUE(product_no, price), ADD CONSTRA -- Tests for constraints without name -- Commands below should error out since constraints do not have the name -ALTER TABLE products ADD UNIQUE(product_no); -ALTER TABLE products ADD PRIMARY KEY(product_no); ALTER TABLE products ADD CHECK(product_no <> 0); -ALTER TABLE products ADD EXCLUDE USING btree (product_no with =); -- ... with names, we can add/drop the constraints just fine ALTER TABLE products ADD CONSTRAINT nonzero_product_no CHECK(product_no <> 0); @@ -576,6 +573,9 @@ DROP SCHEMA sc1 CASCADE; DROP SCHEMA sc2 CASCADE; DROP SCHEMA sc3 CASCADE; +CREATE SCHEMA test_auto_explain; +SET search_path TO 'test_auto_explain'; + -- Test ALTER TABLE ... ADD CONSTRAINT ... does not cause a crash when auto_explain module is loaded CREATE TABLE target_table(col_1 int primary key, col_2 int); SELECT create_distributed_table('target_table','col_1'); @@ -598,3 +598,9 @@ SET citus.enable_ddl_propagation TO OFF; -- alter table triggers SELECT, and auto_explain catches that ALTER TABLE target_table ADD CONSTRAINT fkey_167 FOREIGN KEY (col_1) REFERENCES test_ref_table(key) ON DELETE CASCADE; END; + +RESET citus.enable_ddl_propagation; +SET client_min_messages to ERROR; +SET search_path TO 'public'; + +DROP SCHEMA test_auto_explain CASCADE; diff --git a/src/test/regress/sql/multi_alter_table_add_constraints_without_name.sql b/src/test/regress/sql/multi_alter_table_add_constraints_without_name.sql index 75bcb1bbb..eb38fad8c 100644 --- a/src/test/regress/sql/multi_alter_table_add_constraints_without_name.sql +++ b/src/test/regress/sql/multi_alter_table_add_constraints_without_name.sql @@ -26,7 +26,7 @@ SELECT con.conname WHERE rel.relname = 'products'; -- Check that the primary key name created on the coordinator is sent to workers and --- the constraints created for the shard tables conform to the _shardid scheme. +-- the constraints created for the shard tables conform to the _shardid naming scheme. \c - - :public_worker_1_host :worker_1_port SELECT con.conname FROM pg_catalog.pg_constraint con @@ -37,7 +37,94 @@ SELECT con.conname \c - - :master_host :master_port ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_pkey; -ALTER TABLE AT_AddConstNoName.products ADD PRIMARY KEY(product_no); +-- Check "ADD UNIQUE" +ALTER TABLE AT_AddConstNoName.products ADD UNIQUE(product_no); + +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products'; + +-- Check that UNIQUE constraint name created on the coordinator is sent to workers and +-- the constraints created for the shard tables conform to the _shardid scheme. +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_5410000'; + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_key; + +-- Check "ADD UNIQUE" with column name list +ALTER TABLE AT_AddConstNoName.products ADD UNIQUE(product_no,name); +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products'; + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_5410000'; + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_name_key; + +-- Check "ADD UNIQUE ... INCLUDE" +ALTER TABLE AT_AddConstNoName.products ADD UNIQUE(product_no) INCLUDE(price); + +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products'; + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_5410000'; + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_key; + + +-- Check "ADD UNIQUE NULLS NOT DISTICT" +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int >= 15 AS server_version_ge_15 +\gset +\if :server_version_ge_15 + +ALTER TABLE AT_AddConstNoName.products ADD UNIQUE NULLS NOT DISTINCT (product_no, price); +ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_product_no_price_key; +\endif + +-- Check "ADD EXCLUDE" +CREATE EXTENSION btree_gist; +ALTER TABLE AT_AddConstNoName.products ADD EXCLUDE USING gist (name WITH <> , product_no WITH =); + +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products'; + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_5410000'; + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_name_product_no_excl; DROP TABLE AT_AddConstNoName.products; @@ -63,7 +150,7 @@ CREATE TABLE AT_AddConstNoName.products_ref_3 ( SELECT create_reference_table('AT_AddConstNoName.products_ref'); SELECT create_reference_table('AT_AddConstNoName.products_ref_3'); --- Check for name collisions +-- Check that name collisions are handled for PRIMARY KEY. ALTER TABLE AT_AddConstNoName.products_ref_3 ADD CONSTRAINT products_ref_pkey PRIMARY KEY(name); ALTER TABLE AT_AddConstNoName.products_ref_2 ADD CONSTRAINT products_ref_pkey1 PRIMARY KEY(name); ALTER TABLE AT_AddConstNoName.products_ref ADD PRIMARY KEY(name); @@ -76,9 +163,33 @@ SELECT con.conname ALTER TABLE AT_AddConstNoName.products_ref DROP CONSTRAINT products_ref_pkey2; +-- Check that name collisions are handled for UNIQUE. +ALTER TABLE AT_AddConstNoName.products_ref_3 ADD CONSTRAINT products_ref_name_key UNIQUE(name); +ALTER TABLE AT_AddConstNoName.products_ref_2 ADD CONSTRAINT products_ref_name_key1 UNIQUE(name); +ALTER TABLE AT_AddConstNoName.products_ref ADD UNIQUE(name); + +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_ref'; + +ALTER TABLE AT_AddConstNoName.products_ref DROP CONSTRAINT products_ref_name_key2; + +-- Check that name collisions are handled for EXCLUDE +ALTER TABLE AT_AddConstNoName.products_ref_3 ADD CONSTRAINT products_ref_product_no_excl EXCLUDE (product_no WITH =); +ALTER TABLE AT_AddConstNoName.products_ref_2 ADD CONSTRAINT products_ref_product_no_excl1 EXCLUDE (product_no WITH =); +ALTER TABLE AT_AddConstNoName.products_ref ADD EXCLUDE(product_no WITH =); + +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'products_ref'; + DROP TABLE AT_AddConstNoName.products_ref; --- Check with max table name (63 chars) +-- Check "ADD PRIMARY KEY" with max table name (63 chars) CREATE TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonger ( product_no integer, name text, @@ -108,6 +219,66 @@ SELECT con.conname \c - - :master_host :master_port ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon DROP CONSTRAINT verylonglonglonglonglonglonglonglonglonglonglonglonglonglo_pkey; +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%'; + +-- Check "ADD UNIQUE" with max table name (63 chars) +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon ADD UNIQUE(product_no); + +-- Constraint should be created on the coordinator with a shortened name +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%'; + +-- Constraints for the main table and the shards should be created on the worker with a shortened name +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%' ORDER BY con.conname ASC; + +-- UNIQUE constraint can be deleted via the coordinator +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon DROP CONSTRAINT verylonglonglonglonglonglonglonglonglonglonglong_product_no_key; + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%'; + +-- Check "ADD EXCLUDE" with max table name (63 chars) +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon ADD EXCLUDE (product_no WITH =); + +-- Constraint should be created on the coordinator with a shortened name +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%'; + +-- Constraints for the main table and the shards should be created on the worker with a shortened name +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'very%' ORDER BY con.conname ASC; + +-- EXCLUDE constraint can be deleted via the coordinator +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon DROP CONSTRAINT verylonglonglonglonglonglonglonglonglonglonglon_product_no_excl; + \c - - :public_worker_1_host :worker_1_port SELECT con.conname FROM pg_catalog.pg_constraint con @@ -123,6 +294,7 @@ CREATE TABLE AT_AddConstNoName.p1 PARTITION OF AT_AddConstNoName.dist_partitione CREATE TABLE AT_AddConstNoName.longlonglonglonglonglonglonglonglonglonglonglonglonglonglongabc PARTITION OF AT_AddConstNoName.dist_partitioned_table FOR VALUES FROM ('2020-01-01') TO ('2021-01-01'); SELECT create_distributed_table('AT_AddConstNoName.dist_partitioned_table', 'partition_col'); +-- Check "ADD PRIMARY KEY" SET client_min_messages TO DEBUG1; ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD PRIMARY KEY(partition_col); RESET client_min_messages; @@ -150,8 +322,39 @@ SELECT con.conname INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace WHERE rel.relname LIKE 'longlonglonglonglonglonglonglonglong%' ORDER BY con.conname ASC; --- Test we error out when creating a primary key on a partition table with a long name if we cannot +-- Check "ADD UNIQUE" +\c - - :master_host :master_port +SET client_min_messages TO DEBUG1; +ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD UNIQUE(partition_col); +RESET client_min_messages; + +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'dist_partitioned_table'; + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'longlonglonglonglonglonglonglonglong%' ORDER BY con.conname ASC; + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.dist_partitioned_table DROP CONSTRAINT dist_partitioned_table_partition_col_key; + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'longlonglonglonglonglonglonglonglong%' ORDER BY con.conname ASC; + +-- Test we error out when creating a constraint on a partition table with a long name if we cannot -- switch to sequential execution + +-- Check "ADD PRIMARY KEY" \c - - :master_host :master_port BEGIN; SELECT count(*) FROM AT_AddConstNoName.dist_partitioned_table; @@ -164,9 +367,24 @@ BEGIN; ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD PRIMARY KEY(partition_col); ROLLBACK; +-- Check "ADD UNIQUE" +\c - - :master_host :master_port +BEGIN; + SELECT count(*) FROM AT_AddConstNoName.dist_partitioned_table; + ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD UNIQUE(partition_col); +ROLLBACK; +-- try inside a sequential block +BEGIN; + SET LOCAL citus.multi_shard_modify_mode TO 'sequential'; + SELECT count(*) FROM AT_AddConstNoName.dist_partitioned_table; + ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD UNIQUE(partition_col); + ROLLBACK; + DROP TABLE AT_AddConstNoName.dist_partitioned_table; --- Test primary key name is generated by postgres for citus local table. +-- Test with Citus Local Tables + +-- Test "ADD PRIMARY KEY" \c - - :master_host :master_port SET client_min_messages to ERROR; SELECT 1 FROM master_add_node('localhost', :master_port, groupId => 0); @@ -177,7 +395,7 @@ SELECT citus_add_local_table_to_metadata('AT_AddConstNoName.citus_local_table'); ALTER TABLE AT_AddConstNoName.citus_local_table ADD PRIMARY KEY(id); --- Check the primary key is created for the local table and its shard. +-- Check the primary key is created for the local table and its shard SELECT con.conname FROM pg_catalog.pg_constraint con INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid @@ -186,6 +404,54 @@ SELECT con.conname SELECT create_distributed_table('AT_AddConstNoName.citus_local_table','id'); +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC; + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC; + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.citus_local_table DROP CONSTRAINT citus_local_table_pkey; + +-- Check "ADD UNIQUE" +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.citus_local_table ADD UNIQUE(id); + +-- Check the UNIQUE constraint is created for the local table and its shard +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC; + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC; + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.citus_local_table DROP CONSTRAINT citus_local_table_id_key; + +-- Check "ADD EXCLUDE" +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.citus_local_table ADD EXCLUDE(id WITH =); + +-- Check the EXCLUDE constraint is created for the local table and its shard +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC; + SELECT con.conname FROM pg_catalog.pg_constraint con INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid @@ -208,6 +474,7 @@ CREATE TABLE AT_AddConstNoName.p1 PARTITION OF AT_AddConstNoName.citus_local_par CREATE TABLE AT_AddConstNoName.longlonglonglonglonglonglonglonglonglonglonglonglonglonglongabc PARTITION OF AT_AddConstNoName.citus_local_partitioned_table FOR VALUES FROM ('2020-01-01') TO ('2021-01-01'); SELECT citus_add_local_table_to_metadata('AT_AddConstNoName.citus_local_partitioned_table'); +-- Check "ADD PRIMARY KEY" ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD PRIMARY KEY(partition_col); SELECT create_distributed_table('AT_AddConstNoName.citus_local_partitioned_table', 'partition_col'); @@ -234,12 +501,41 @@ SELECT con.conname \c - - :master_host :master_port ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table DROP CONSTRAINT citus_local_partitioned_table_pkey; +-- Check "ADD UNIQUE" +ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD UNIQUE(partition_col); + +ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table DROP CONSTRAINT citus_local_partitioned_table_partition_col_key; + +SET client_min_messages TO DEBUG1; +ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD UNIQUE(partition_col); +RESET client_min_messages; + +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = 'citus_local_partitioned_table'; + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE 'longlonglonglonglonglonglonglonglong%' ORDER BY con.conname ASC; + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table DROP CONSTRAINT citus_local_partitioned_table_partition_col_key; + +-- Check "ADD EXCLUDE" errors out for partitioned table since the postgres does not allow it +ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD EXCLUDE(partition_col WITH =); + SELECT 1 FROM master_remove_node('localhost', :master_port); -- Test with unusual table and column names CREATE TABLE AT_AddConstNoName."2nd table" ( "2nd id" INTEGER, "3rd id" INTEGER); SELECT create_distributed_table('AT_AddConstNoName."2nd table"','2nd id'); +-- Check "ADD PRIMARY KEY" ALTER TABLE AT_AddConstNoName."2nd table" ADD PRIMARY KEY ("2nd id", "3rd id"); SELECT con.conname FROM pg_catalog.pg_constraint con @@ -258,4 +554,45 @@ SELECT con.conname \c - - :master_host :master_port ALTER TABLE AT_AddConstNoName."2nd table" DROP CONSTRAINT "2nd table_pkey"; +-- Check "ADD UNIQUE" +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName."2nd table" ADD UNIQUE ("2nd id", "3rd id"); + +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = '2nd table'; + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE '2nd table%' ORDER BY con.conname ASC; + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName."2nd table" DROP CONSTRAINT "2nd table_2nd id_3rd id_key"; + +-- Check "ADD EXCLUDE" +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName."2nd table" ADD EXCLUDE ("2nd id" WITH =); + +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname = '2nd table'; + +\c - - :public_worker_1_host :worker_1_port +SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace + WHERE rel.relname LIKE '2nd table%' ORDER BY con.conname ASC; + +\c - - :master_host :master_port +ALTER TABLE AT_AddConstNoName."2nd table" DROP CONSTRAINT "2nd table_2nd id_excl"; + +DROP EXTENSION btree_gist; DROP SCHEMA AT_AddConstNoName CASCADE; diff --git a/src/test/regress/sql/multi_name_lengths.sql b/src/test/regress/sql/multi_name_lengths.sql index 9dbb515ba..3da879157 100644 --- a/src/test/regress/sql/multi_name_lengths.sql +++ b/src/test/regress/sql/multi_name_lengths.sql @@ -46,8 +46,6 @@ ALTER TABLE name_lengths ADD COLUMN date_col_12345678901234567890123456789012345 ALTER TABLE name_lengths ADD COLUMN int_col_12345678901234567890123456789012345678901234567890 INTEGER DEFAULT 1; -- Placeholders for unsupported ALTER TABLE to add constraints with implicit names that are likely too long -ALTER TABLE name_lengths ADD UNIQUE (float_col_12345678901234567890123456789012345678901234567890); -ALTER TABLE name_lengths ADD EXCLUDE (int_col_12345678901234567890123456789012345678901234567890 WITH =); ALTER TABLE name_lengths ADD CHECK (date_col_12345678901234567890123456789012345678901234567890 > '2014-01-01'::date); \c - - :public_worker_1_host :worker_1_port