Enable PRIMARY KEY generation via ALTER TABLE even if the constraint name is not provided (#6520)

DESCRIPTION: Support ALTER TABLE .. ADD PRIMARY KEY ... command

Before processing
	> **ALTER TABLE ... ADD PRIMARY KEY ...**
command

1. 	Create a primary key name to use as the constraint name.
2. Change the **ALTER TABLE ... ADD PRIMARY KEY ...** command to into
**ALTER TABLE ... ADD CONSTRAINT \<constraint name> PRIMARY KEY ...**
form.
This is the only form we can specify a name for a primary key. If we run
ALTER TABLE .. ADD PRIMARY KEY, postgres
would create a constraint name internally in its own scheme. But the
problem is that we need to create constraint names
for shards in our own scheme which is \<constraint name>_\<shardid>.
Hence we need to create a name and send it to workers so that the
workers can append the shardid.
4. Run the changed command on the coordinator to make sure we are using
the same constraint name across the board.
5. Send the changed command to workers such that it is executed for the
main table as well as for the shards.

Fixes #6515.
pull/6365/head
Emel Şimşek 2022-12-16 20:34:00 +03:00 committed by GitHub
parent 9c0073ba57
commit 5268d0a6cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1133 additions and 9 deletions

View File

@ -29,6 +29,7 @@
#include "distributed/deparse_shard_query.h"
#include "distributed/distribution_column.h"
#include "distributed/foreign_key_relationship.h"
#include "distributed/local_executor.h"
#include "distributed/listutils.h"
#include "distributed/metadata_sync.h"
#include "distributed/metadata/dependency.h"
@ -700,6 +701,129 @@ PostprocessAlterTableSchemaStmt(Node *node, const char *queryString)
}
/*
* SwitchToSequentialAndLocalExecutionIfPrimaryKeyNameTooLong generates the longest primary key 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)
{
if (!PartitionedTable(relationId))
{
/* Citus already handles long names for regular tables */
return;
}
if (ShardIntervalCount(relationId) == 0)
{
/*
* Relation has no shards, so we cannot run into "long shard index
* name" issue.
*/
return;
}
Oid longestNamePartitionId = PartitionWithLongestNameRelationId(relationId);
if (!OidIsValid(longestNamePartitionId))
{
/* no partitions have been created yet */
return;
}
char *longestPartitionShardName = get_rel_name(longestNamePartitionId);
ShardInterval *shardInterval = LoadShardIntervalWithLongestShardName(
longestNamePartitionId);
AppendShardIdToName(&longestPartitionShardName, shardInterval->shardId);
Relation rel = RelationIdGetRelation(longestNamePartitionId);
Oid namespaceOid = RelationGetNamespace(rel);
RelationClose(rel);
char *primaryKeyName = ChooseIndexName(longestPartitionShardName,
namespaceOid,
NULL, NULL, true, true);
if (primaryKeyName && strnlen(primaryKeyName, NAMEDATALEN) >= NAMEDATALEN - 1)
{
if (ParallelQueryExecutedInTransaction())
{
/*
* If there has already been a parallel query executed, the sequential mode
* would still use the already opened parallel connections to the workers,
* 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 "
"to deadlocks when executed in a transaction "
"block after a parallel query", primaryKeyName),
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 "
"is too long, switching to sequential and local execution "
"mode to prevent self deadlocks: %s", primaryKeyName);
SetLocalMultiShardModifyModeToSequential();
SetLocalExecutionStatus(LOCAL_EXECUTION_REQUIRED);
}
}
}
/*
* 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 <constraint name> PRIMARY KEY format and returns the DDLJob
* to run this command in the workers.
*/
static List *
PreprocessAlterTableAddPrimaryKey(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
* 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);
RelationClose(rel);
char *ddlCommand = DeparseTreeNode((Node *) alterTableStatement);
SwitchToSequentialAndLocalExecutionIfPrimaryKeyNameTooLong(relationId);
DDLJob *ddlJob = palloc0(sizeof(DDLJob));
ObjectAddressSet(ddlJob->targetObjectAddress, RelationRelationId, relationId);
ddlJob->startNewTransaction = false;
ddlJob->metadataSyncCommand = ddlCommand;
ddlJob->taskList = DDLTaskList(relationId, ddlCommand);
return list_make1(ddlJob);
}
/*
* PreprocessAlterTableStmt determines whether a given ALTER TABLE statement
* involves a distributed table. If so (and if the statement does not use
@ -939,6 +1063,19 @@ PreprocessAlterTableStmt(Node *node, const char *alterTableCommand,
*/
constraint->skip_validation = true;
}
else if (constraint->contype == CONSTR_PRIMARY)
{
if (constraint->conname == NULL)
{
/*
* Create a constraint name. Convert ALTER TABLE ... ADD PRIMARY ... command into
* ALTER TABLE ... ADD CONSTRAINT <conname> PRIMARY KEY ... form and create the ddl jobs
* for running this form of the command on the workers.
*/
return PreprocessAlterTableAddPrimaryKey(alterTableStatement,
leftRelationId, constraint);
}
}
}
else if (alterTableType == AT_DropConstraint)
{
@ -2883,9 +3020,18 @@ ErrorIfUnsupportedAlterTableStmt(AlterTableStmt *alterTableStatement)
*/
if (constraint->conname == NULL)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot create constraint without a name on a "
"distributed table")));
/*
* We support ALTER TABLE ... ADD PRIMARY ... commands by creating a constraint name
* and changing the command into the following form.
* ALTER TABLE ... ADD CONSTRAINT <constaint_name> PRIMARY KEY ...
*/
if (constraint->contype != CONSTR_PRIMARY)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg(
"cannot create constraint without a name on a "
"distributed table")));
}
}
break;

View File

@ -119,6 +119,48 @@ AppendAlterTableCmd(StringInfo buf, AlterTableCmd *alterTableCmd)
break;
}
case AT_AddConstraint:
{
Constraint *constraint = (Constraint *) alterTableCmd->def;
/* We need to deparse ALTER TABLE ... PRIMARY KEY commands into
* ALTER TABLE ... ADD CONSTRAINT <conname> PRIMARY KEY ... to be able
* add a constraint name.
*/
if (constraint->contype == CONSTR_PRIMARY)
{
/* 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, ")");
break;
}
}
/* fallthrough */
default:
{
ereport(ERROR, (errmsg("unsupported subtype for alter table command"),

View File

@ -165,6 +165,9 @@ class CitusDefaultClusterConfig(CitusBaseClusterConfig):
}
self.settings.update(new_settings)
self.add_coordinator_to_metadata = True
self.skip_tests = [
# Alter Table statement cannot be run from an arbitrary node so this test will fail
"arbitrary_configs_alter_table_add_constraint_without_name_create", "arbitrary_configs_alter_table_add_constraint_without_name"]
class CitusUpgradeConfig(CitusBaseClusterConfig):
@ -187,8 +190,9 @@ class PostgresConfig(CitusDefaultClusterConfig):
self.new_settings = {
"citus.use_citus_managed_tables": False,
}
self.skip_tests = ["nested_execution"]
self.skip_tests = ["nested_execution",
# Alter Table statement cannot be run from an arbitrary node so this test will fail
"arbitrary_configs_alter_table_add_constraint_without_name_create", "arbitrary_configs_alter_table_add_constraint_without_name"]
class CitusSingleNodeClusterConfig(CitusDefaultClusterConfig):
def __init__(self, arguments):
@ -303,8 +307,9 @@ class CitusUnusualQuerySettingsConfig(CitusDefaultClusterConfig):
# requires the table with the fk to be converted to a citus_local_table.
# As of c11, there is no way to do that through remote execution so this test
# will fail
"arbitrary_configs_truncate_cascade_create", "arbitrary_configs_truncate_cascade"]
"arbitrary_configs_truncate_cascade_create", "arbitrary_configs_truncate_cascade",
# Alter Table statement cannot be run from an arbitrary node so this test will fail
"arbitrary_configs_alter_table_add_constraint_without_name_create", "arbitrary_configs_alter_table_add_constraint_without_name"]
class CitusSingleNodeSingleShardClusterConfig(CitusDefaultClusterConfig):
def __init__(self, arguments):
@ -329,7 +334,9 @@ class CitusShardReplicationFactorClusterConfig(CitusDefaultClusterConfig):
"arbitrary_configs_truncate_cascade_create", "arbitrary_configs_truncate_cascade",
# citus does not support colocating functions with distributed tables when
# citus.shard_replication_factor >= 2
"function_create", "functions"]
"function_create", "functions",
# Alter Table statement cannot be run from an arbitrary node so this test will fail
"arbitrary_configs_alter_table_add_constraint_without_name_create", "arbitrary_configs_alter_table_add_constraint_without_name"]
class CitusSingleShardClusterConfig(CitusDefaultClusterConfig):

View File

@ -12,3 +12,4 @@ test: function_create
test: arbitrary_configs_truncate_create
test: arbitrary_configs_truncate_cascade_create
test: arbitrary_configs_truncate_partition_create
test: arbitrary_configs_alter_table_add_constraint_without_name_create

View File

@ -0,0 +1,76 @@
--
-- MULTI_ALTER_TABLE_ADD_CONSTRAINTS_WITHOUT_NAME
--
-- Test checks whether constraints of distributed tables can be adjusted using
-- the ALTER TABLE ... ADD without specifying a name.
SET search_path TO sc1;
-- Check "ADD PRIMARY KEY"
ALTER TABLE products ADD PRIMARY KEY(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_pkey
(1 row)
ALTER TABLE products DROP CONSTRAINT products_pkey;
ALTER TABLE products ADD PRIMARY KEY(product_no);
-- Check "ADD PRIMARY KEY" with reference table
-- Check for name collisions
ALTER TABLE products_ref_3 ADD CONSTRAINT products_ref_pkey PRIMARY KEY(name);
ALTER TABLE products_ref_2 ADD CONSTRAINT products_ref_pkey1 PRIMARY KEY(name);
ALTER TABLE products_ref ADD PRIMARY KEY(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_pkey2
(1 row)
ALTER TABLE products_ref DROP CONSTRAINT products_ref_pkey2;
-- Check with max table name (63 chars)
ALTER TABLE verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon ADD PRIMARY KEY(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
---------------------------------------------------------------------
verylonglonglonglonglonglonglonglonglonglonglonglonglonglo_pkey
(1 row)
ALTER TABLE verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon DROP CONSTRAINT verylonglonglonglonglonglonglonglonglonglonglonglonglonglo_pkey;
-- 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
ALTER TABLE dist_partitioned_table ADD PRIMARY KEY(partition_col);
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_pkey
(1 row)
ALTER TABLE dist_partitioned_table DROP CONSTRAINT dist_partitioned_table_pkey;
-- Test primary key name is generated by postgres for citus local table.
ALTER TABLE citus_local_table ADD PRIMARY KEY(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 = 'citus_local_table';
conname
---------------------------------------------------------------------
citus_local_table_pkey
(1 row)

View File

@ -0,0 +1,71 @@
--
-- MULTI_ALTER_TABLE_ADD_CONSTRAINTS_WITHOUT_NAME
--
-- Test checks whether constraints of distributed tables can be adjusted using
-- the ALTER TABLE ... ADD without specifying a name.
-- Check "ADD PRIMARY KEY"
CREATE SCHEMA sc1;
SET search_path TO sc1;
CREATE TABLE products (
product_no integer,
name text,
price numeric
);
SELECT create_distributed_table('products', 'product_no');
create_distributed_table
---------------------------------------------------------------------
(1 row)
CREATE TABLE sc1.products_ref (
product_no integer,
name text,
price numeric
);
CREATE TABLE products_ref_2 (
product_no integer,
name text,
price numeric
);
CREATE TABLE products_ref_3 (
product_no integer,
name text,
price numeric
);
SELECT create_reference_table('products_ref');
create_reference_table
---------------------------------------------------------------------
(1 row)
SELECT create_reference_table('products_ref_3');
create_reference_table
---------------------------------------------------------------------
(1 row)
-- Check with max table name (63 chars)
CREATE TABLE verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonger (
product_no integer,
name text,
price numeric
);
SELECT create_distributed_table('verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon', 'product_no');
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- 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
CREATE TABLE dist_partitioned_table (dist_col int, another_col int, partition_col timestamp) PARTITION BY RANGE (partition_col);
CREATE TABLE p1 PARTITION OF dist_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2022-01-01');
CREATE TABLE longlonglonglonglonglonglonglonglonglonglonglonglonglonglongabc PARTITION OF dist_partitioned_table FOR VALUES FROM ('2020-01-01') TO ('2021-01-01');
SELECT create_distributed_table('dist_partitioned_table', 'partition_col');
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- Test primary key name is generated by postgres for citus local table.
CREATE TABLE citus_local_table(id int, other_column int);

View File

@ -437,7 +437,6 @@ HINT: You can issue each subcommand separately
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);
ERROR: cannot create constraint without a name on a distributed table
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 =);

View File

@ -0,0 +1,396 @@
--
-- MULTI_ALTER_TABLE_ADD_CONSTRAINTS_WITHOUT_NAME
--
-- Test checks whether constraints of distributed tables can be adjusted using
-- the ALTER TABLE ... ADD without specifying a name.
ALTER SEQUENCE pg_catalog.pg_dist_shardid_seq RESTART 5410000;
ALTER SEQUENCE pg_catalog.pg_dist_placement_placementid_seq RESTART 5410000;
CREATE SCHEMA AT_AddConstNoName;
-- Check "ADD PRIMARY KEY"
CREATE TABLE AT_AddConstNoName.products (
product_no integer,
name text,
price numeric
);
SELECT create_distributed_table('AT_AddConstNoName.products', 'product_no');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE AT_AddConstNoName.products ADD PRIMARY KEY(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_pkey
(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 <conname>_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_pkey_5410000
(1 row)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_pkey;
ALTER TABLE AT_AddConstNoName.products ADD PRIMARY KEY(product_no);
DROP TABLE AT_AddConstNoName.products;
-- Check "ADD PRIMARY KEY" with reference table
CREATE TABLE AT_AddConstNoName.products_ref (
product_no integer,
name text,
price numeric
);
CREATE TABLE AT_AddConstNoName.products_ref_2 (
product_no integer,
name text,
price numeric
);
CREATE TABLE AT_AddConstNoName.products_ref_3 (
product_no integer,
name text,
price numeric
);
SELECT create_reference_table('AT_AddConstNoName.products_ref');
create_reference_table
---------------------------------------------------------------------
(1 row)
SELECT create_reference_table('AT_AddConstNoName.products_ref_3');
create_reference_table
---------------------------------------------------------------------
(1 row)
-- Check for name collisions
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);
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_pkey2
(1 row)
ALTER TABLE AT_AddConstNoName.products_ref DROP CONSTRAINT products_ref_pkey2;
DROP TABLE AT_AddConstNoName.products_ref;
-- Check with max table name (63 chars)
CREATE TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonger (
product_no integer,
name text,
price numeric
);
NOTICE: identifier "verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonger" will be truncated to "verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon"
SELECT create_distributed_table('AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon', 'product_no');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon ADD PRIMARY KEY(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
---------------------------------------------------------------------
verylonglonglonglonglonglonglonglonglonglonglonglonglonglo_pkey
(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_559ab79d_5410006
verylonglonglonglonglonglonglonglonglonglonglo_559ab79d_5410007
verylonglonglonglonglonglonglonglonglonglonglo_559ab79d_5410008
verylonglonglonglonglonglonglonglonglonglonglo_559ab79d_5410009
verylonglonglonglonglonglonglonglonglonglonglonglonglonglo_pkey
(5 rows)
-- Constraint can be deleted via the coordinator
\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%';
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
CREATE TABLE AT_AddConstNoName.dist_partitioned_table (dist_col int, another_col int, partition_col timestamp) PARTITION BY RANGE (partition_col);
CREATE TABLE AT_AddConstNoName.p1 PARTITION OF AT_AddConstNoName.dist_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2022-01-01');
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');
create_distributed_table
---------------------------------------------------------------------
(1 row)
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: 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"
DEBUG: verifying table "p1"
DEBUG: verifying table "longlonglonglonglonglonglonglonglonglonglonglonglonglonglongabc"
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_pkey
(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
---------------------------------------------------------------------
longlonglonglonglonglonglonglonglonglonglonglo_9e4e3069_5410014
longlonglonglonglonglonglonglonglonglonglonglo_9e4e3069_5410015
longlonglonglonglonglonglonglonglonglonglonglo_9e4e3069_5410016
longlonglonglonglonglonglonglonglonglonglonglo_9e4e3069_5410017
longlonglonglonglonglonglonglonglonglonglonglonglonglonglo_pkey
(5 rows)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.dist_partitioned_table DROP CONSTRAINT dist_partitioned_table_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 'longlonglonglonglonglonglonglonglong%' ORDER BY con.conname ASC;
conname
---------------------------------------------------------------------
(0 rows)
-- Test we error out when creating a primary key on a partition table with a long name if we cannot
-- switch to sequential execution
\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 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
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 PRIMARY KEY(partition_col);
ROLLBACK;
DROP TABLE AT_AddConstNoName.dist_partitioned_table;
-- Test primary key name is generated by postgres for citus local table.
\c - - :master_host :master_port
SET client_min_messages to ERROR;
SELECT 1 FROM master_add_node('localhost', :master_port, groupId => 0);
?column?
---------------------------------------------------------------------
1
(1 row)
RESET client_min_messages;
CREATE TABLE AT_AddConstNoName.citus_local_table(id int, other_column int);
SELECT citus_add_local_table_to_metadata('AT_AddConstNoName.citus_local_table');
citus_add_local_table_to_metadata
---------------------------------------------------------------------
(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.
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_pkey
citus_local_table_pkey_5410022
(2 rows)
SELECT create_distributed_table('AT_AddConstNoName.citus_local_table','id');
create_distributed_table
---------------------------------------------------------------------
(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_pkey
(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_pkey
citus_local_table_pkey_5410023
citus_local_table_pkey_5410024
citus_local_table_pkey_5410025
citus_local_table_pkey_5410026
(5 rows)
\c - - :master_host :master_port
DROP TABLE AT_AddConstNoName.citus_local_table;
-- Test with partitioned citus local table
CREATE TABLE AT_AddConstNoName.citus_local_partitioned_table (dist_col int, another_col int, partition_col timestamp) PARTITION BY RANGE (partition_col);
CREATE TABLE AT_AddConstNoName.p1 PARTITION OF AT_AddConstNoName.citus_local_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2022-01-01');
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');
citus_add_local_table_to_metadata
---------------------------------------------------------------------
(1 row)
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
---------------------------------------------------------------------
(1 row)
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: 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"
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_pkey
(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
---------------------------------------------------------------------
longlonglonglonglonglonglonglonglonglonglonglo_9e4e3069_5410034
longlonglonglonglonglonglonglonglonglonglonglo_9e4e3069_5410035
longlonglonglonglonglonglonglonglonglonglonglo_9e4e3069_5410036
longlonglonglonglonglonglonglonglonglonglonglo_9e4e3069_5410037
longlonglonglonglonglonglonglonglonglonglonglonglonglonglo_pkey
(5 rows)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table DROP CONSTRAINT citus_local_partitioned_table_pkey;
SELECT 1 FROM master_remove_node('localhost', :master_port);
?column?
---------------------------------------------------------------------
1
(1 row)
-- 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');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE AT_AddConstNoName."2nd table" ADD PRIMARY KEY ("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_pkey
(1 row)
-- Check if a primary key constraint is created for the shard tables on the workers
\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_pkey
2nd table_pkey_5410042
2nd table_pkey_5410043
2nd table_pkey_5410044
2nd table_pkey_5410045
(5 rows)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName."2nd table" DROP CONSTRAINT "2nd table_pkey";
DROP SCHEMA AT_AddConstNoName CASCADE;
NOTICE: drop cascades to 6 other objects
DETAIL: drop cascades to table at_addconstnoname.products_ref_2
drop cascades to table at_addconstnoname.products_ref_3
drop cascades to table at_addconstnoname.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon
drop cascades to table at_addconstnoname.products_ref_3_5410005
drop cascades to table at_addconstnoname.citus_local_partitioned_table
drop cascades to table at_addconstnoname."2nd table"

View File

@ -151,6 +151,7 @@ test: with_executors with_join with_partitioning with_transactions with_dml
test: multi_index_statements
test: multi_alter_table_statements
test: multi_alter_table_add_constraints
test: multi_alter_table_add_constraints_without_name
# ----------
# Tests to check if we inform the user about potential caveats of creating new

View File

@ -0,0 +1,66 @@
--
-- MULTI_ALTER_TABLE_ADD_CONSTRAINTS_WITHOUT_NAME
--
-- Test checks whether constraints of distributed tables can be adjusted using
-- the ALTER TABLE ... ADD without specifying a name.
SET search_path TO sc1;
-- Check "ADD PRIMARY KEY"
ALTER TABLE products ADD PRIMARY KEY(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';
ALTER TABLE products DROP CONSTRAINT products_pkey;
ALTER TABLE products ADD PRIMARY KEY(product_no);
-- Check "ADD PRIMARY KEY" with reference table
-- Check for name collisions
ALTER TABLE products_ref_3 ADD CONSTRAINT products_ref_pkey PRIMARY KEY(name);
ALTER TABLE products_ref_2 ADD CONSTRAINT products_ref_pkey1 PRIMARY KEY(name);
ALTER TABLE products_ref ADD PRIMARY KEY(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 products_ref DROP CONSTRAINT products_ref_pkey2;
-- Check with max table name (63 chars)
ALTER TABLE verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon ADD PRIMARY KEY(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%';
ALTER TABLE verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon DROP CONSTRAINT verylonglonglonglonglonglonglonglonglonglonglonglonglonglo_pkey;
-- 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
ALTER TABLE dist_partitioned_table ADD PRIMARY KEY(partition_col);
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';
ALTER TABLE dist_partitioned_table DROP CONSTRAINT dist_partitioned_table_pkey;
-- Test primary key name is generated by postgres for citus local table.
ALTER TABLE citus_local_table ADD PRIMARY KEY(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 = 'citus_local_table';

View File

@ -0,0 +1,57 @@
--
-- MULTI_ALTER_TABLE_ADD_CONSTRAINTS_WITHOUT_NAME
--
-- Test checks whether constraints of distributed tables can be adjusted using
-- the ALTER TABLE ... ADD without specifying a name.
-- Check "ADD PRIMARY KEY"
CREATE SCHEMA sc1;
SET search_path TO sc1;
CREATE TABLE products (
product_no integer,
name text,
price numeric
);
SELECT create_distributed_table('products', 'product_no');
CREATE TABLE sc1.products_ref (
product_no integer,
name text,
price numeric
);
CREATE TABLE products_ref_2 (
product_no integer,
name text,
price numeric
);
CREATE TABLE products_ref_3 (
product_no integer,
name text,
price numeric
);
SELECT create_reference_table('products_ref');
SELECT create_reference_table('products_ref_3');
-- Check with max table name (63 chars)
CREATE TABLE verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonger (
product_no integer,
name text,
price numeric
);
SELECT create_distributed_table('verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon', 'product_no');
-- 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
CREATE TABLE dist_partitioned_table (dist_col int, another_col int, partition_col timestamp) PARTITION BY RANGE (partition_col);
CREATE TABLE p1 PARTITION OF dist_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2022-01-01');
CREATE TABLE longlonglonglonglonglonglonglonglonglonglonglonglonglonglongabc PARTITION OF dist_partitioned_table FOR VALUES FROM ('2020-01-01') TO ('2021-01-01');
SELECT create_distributed_table('dist_partitioned_table', 'partition_col');
-- Test primary key name is generated by postgres for citus local table.
CREATE TABLE citus_local_table(id int, other_column int);

View File

@ -0,0 +1,261 @@
--
-- MULTI_ALTER_TABLE_ADD_CONSTRAINTS_WITHOUT_NAME
--
-- Test checks whether constraints of distributed tables can be adjusted using
-- the ALTER TABLE ... ADD without specifying a name.
ALTER SEQUENCE pg_catalog.pg_dist_shardid_seq RESTART 5410000;
ALTER SEQUENCE pg_catalog.pg_dist_placement_placementid_seq RESTART 5410000;
CREATE SCHEMA AT_AddConstNoName;
-- Check "ADD PRIMARY KEY"
CREATE TABLE AT_AddConstNoName.products (
product_no integer,
name text,
price numeric
);
SELECT create_distributed_table('AT_AddConstNoName.products', 'product_no');
ALTER TABLE AT_AddConstNoName.products ADD PRIMARY KEY(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 the primary key name created on the coordinator is sent to workers and
-- the constraints created for the shard tables conform to the <conname>_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_pkey;
ALTER TABLE AT_AddConstNoName.products ADD PRIMARY KEY(product_no);
DROP TABLE AT_AddConstNoName.products;
-- Check "ADD PRIMARY KEY" with reference table
CREATE TABLE AT_AddConstNoName.products_ref (
product_no integer,
name text,
price numeric
);
CREATE TABLE AT_AddConstNoName.products_ref_2 (
product_no integer,
name text,
price numeric
);
CREATE TABLE AT_AddConstNoName.products_ref_3 (
product_no integer,
name text,
price numeric
);
SELECT create_reference_table('AT_AddConstNoName.products_ref');
SELECT create_reference_table('AT_AddConstNoName.products_ref_3');
-- Check for name collisions
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);
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_pkey2;
DROP TABLE AT_AddConstNoName.products_ref;
-- Check with max table name (63 chars)
CREATE TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonger (
product_no integer,
name text,
price numeric
);
SELECT create_distributed_table('AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon', 'product_no');
ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon ADD PRIMARY KEY(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;
-- Constraint can be deleted via the coordinator
\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%';
-- 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
CREATE TABLE AT_AddConstNoName.dist_partitioned_table (dist_col int, another_col int, partition_col timestamp) PARTITION BY RANGE (partition_col);
CREATE TABLE AT_AddConstNoName.p1 PARTITION OF AT_AddConstNoName.dist_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2022-01-01');
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');
SET client_min_messages TO DEBUG1;
ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD PRIMARY KEY(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_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 '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
-- switch to sequential execution
\c - - :master_host :master_port
BEGIN;
SELECT count(*) FROM AT_AddConstNoName.dist_partitioned_table;
ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD PRIMARY KEY(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 PRIMARY KEY(partition_col);
ROLLBACK;
DROP TABLE AT_AddConstNoName.dist_partitioned_table;
-- Test primary key name is generated by postgres for citus local table.
\c - - :master_host :master_port
SET client_min_messages to ERROR;
SELECT 1 FROM master_add_node('localhost', :master_port, groupId => 0);
RESET client_min_messages;
CREATE TABLE AT_AddConstNoName.citus_local_table(id int, other_column int);
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.
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 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
DROP TABLE AT_AddConstNoName.citus_local_table;
-- Test with partitioned citus local table
CREATE TABLE AT_AddConstNoName.citus_local_partitioned_table (dist_col int, another_col int, partition_col timestamp) PARTITION BY RANGE (partition_col);
CREATE TABLE AT_AddConstNoName.p1 PARTITION OF AT_AddConstNoName.citus_local_partitioned_table FOR VALUES FROM ('2021-01-01') TO ('2022-01-01');
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');
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');
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);
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_pkey;
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');
ALTER TABLE AT_AddConstNoName."2nd table" ADD PRIMARY KEY ("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';
-- Check if a primary key constraint is created for the shard tables on the workers
\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_pkey";
DROP SCHEMA AT_AddConstNoName CASCADE;

View File

@ -13,3 +13,4 @@ test: functions
test: arbitrary_configs_truncate
test: arbitrary_configs_truncate_cascade
test: arbitrary_configs_truncate_partition
test: arbitrary_configs_alter_table_add_constraint_without_name