mirror of https://github.com/citusdata/citus.git
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
parent
9c0073ba57
commit
5268d0a6cb
|
@ -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;
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
@ -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);
|
|
@ -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 =);
|
||||
|
|
|
@ -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"
|
|
@ -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
|
||||
|
|
|
@ -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';
|
|
@ -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);
|
|
@ -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;
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue