Enable ALTER TABLE ... ADD CHECK (#6606)

DESCRIPTION: Enable adding CHECK constraints on distributed tables
without the client having to provide a constraint name.

This PR enables the following command syntax for adding check
constraints to distributed tables.
 ALTER TABLE ... ADD CHECK ... 

by creating a default constraint name and transforming the command into
the below syntax before sending it to workers.

ALTER TABLE ... ADD CONSTRAINT \<conname> CHECK ...
Enable-ADD-FOREIGN-KEY
Emel Şimşek 2023-01-12 23:31:06 +03:00 committed by GitHub
parent a6ad4574f6
commit 28ed013a91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 537 additions and 22 deletions

View File

@ -29,7 +29,6 @@
static const char * unparse_policy_command(const char aclchar);
static void AddRangeTableEntryToQueryCompat(ParseState *parseState, Relation relation);
static RowSecurityPolicy * GetPolicyByName(Oid relationId, const char *policyName);
static List * GetPolicyListForRelation(Oid relationId);
static char * CreatePolicyCommandForPolicy(Oid relationId, RowSecurityPolicy *policy);
@ -287,7 +286,7 @@ PostprocessCreatePolicyStmt(Node *node, const char *queryString)
* AddRangeTableEntryToQueryCompat adds the given relation to query.
* This method is a compatibility wrapper.
*/
static void
void
AddRangeTableEntryToQueryCompat(ParseState *parseState, Relation relation)
{
ParseNamespaceItem *rte = addRangeTableEntryForRelation(parseState, relation,

View File

@ -762,6 +762,13 @@ GenerateConstraintName(const char *tabname, Oid namespaceId, Constraint *constra
break;
}
case CONSTR_CHECK:
{
conname = ChooseConstraintName(tabname, NULL, "check", namespaceId, NULL);
break;
}
default:
{
ereport(ERROR, (errmsg(
@ -1906,7 +1913,8 @@ ConstrTypeCitusCanDefaultName(ConstrType constrType)
{
return constrType == CONSTR_PRIMARY ||
constrType == CONSTR_UNIQUE ||
constrType == CONSTR_EXCLUSION;
constrType == CONSTR_EXCLUSION ||
constrType == CONSTR_CHECK;
}

View File

@ -16,12 +16,20 @@
#include "distributed/version_compat.h"
#include "nodes/nodes.h"
#include "nodes/parsenodes.h"
#include "parser/parse_expr.h"
#include "parser/parse_type.h"
#include "parser/parse_relation.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/ruleutils.h"
#include "distributed/namespace_utils.h"
#include "commands/tablecmds.h"
static void AppendAlterTableSchemaStmt(StringInfo buf, AlterObjectSchemaStmt *stmt);
static void AppendAlterTableStmt(StringInfo buf, AlterTableStmt *stmt);
static void AppendAlterTableCmd(StringInfo buf, AlterTableCmd *alterTableCmd);
static void AppendAlterTableCmd(StringInfo buf, AlterTableCmd *alterTableCmd,
AlterTableStmt *stmt);
static void AppendAlterTableCmdAddColumn(StringInfo buf, AlterTableCmd *alterTableCmd);
char *
@ -97,7 +105,7 @@ AppendAlterTableStmt(StringInfo buf, AlterTableStmt *stmt)
}
AlterTableCmd *alterTableCmd = castNode(AlterTableCmd, lfirst(cmdCell));
AppendAlterTableCmd(buf, alterTableCmd);
AppendAlterTableCmd(buf, alterTableCmd, stmt);
}
appendStringInfoString(buf, ";");
@ -109,7 +117,8 @@ AppendAlterTableStmt(StringInfo buf, AlterTableStmt *stmt)
* in the ADD CONSTRAINT <conname> {PRIMARY KEY, UNIQUE, EXCLUSION} form and appends it to the buf.
*/
static void
AppendAlterTableCmdAddConstraint(StringInfo buf, Constraint *constraint)
AppendAlterTableCmdAddConstraint(StringInfo buf, Constraint *constraint,
AlterTableStmt *stmt)
{
/* Need to deparse the alter table constraint command only if we are adding a constraint name.*/
if (constraint->conname == NULL)
@ -229,6 +238,41 @@ AppendAlterTableCmdAddConstraint(StringInfo buf, Constraint *constraint)
appendStringInfoString(buf, " )");
}
else if (constraint->contype == CONSTR_CHECK)
{
LOCKMODE lockmode = AlterTableGetLockLevel(stmt->cmds);
Oid leftRelationId = AlterTableLookupRelation(stmt, lockmode);
/* To be able to use deparse_expression function, which creates an expression string,
* the expression should be provided in its cooked form. We transform the raw expression
* to cooked form.
*/
ParseState *pstate = make_parsestate(NULL);
Relation relation = table_open(leftRelationId, AccessShareLock);
/* Add table name to the name space in parse state. Otherwise column names
* cannot be found.
*/
AddRangeTableEntryToQueryCompat(pstate, relation);
Node *exprCooked = transformExpr(pstate, constraint->raw_expr,
EXPR_KIND_CHECK_CONSTRAINT);
char *relationName = get_rel_name(leftRelationId);
List *relationCtx = deparse_context_for(relationName, leftRelationId);
char *exprSql = deparse_expression(exprCooked, relationCtx, false, false);
relation_close(relation, NoLock);
appendStringInfo(buf, " CHECK (%s)", exprSql);
if (constraint->is_no_inherit)
{
appendStringInfo(buf, " NO INHERIT");
}
}
if (constraint->deferrable)
{
@ -248,7 +292,7 @@ AppendAlterTableCmdAddConstraint(StringInfo buf, Constraint *constraint)
* AT_AddColumn, AT_SetNotNull and AT_AddConstraint {PRIMARY KEY, UNIQUE, EXCLUDE}.
*/
static void
AppendAlterTableCmd(StringInfo buf, AlterTableCmd *alterTableCmd)
AppendAlterTableCmd(StringInfo buf, AlterTableCmd *alterTableCmd, AlterTableStmt *stmt)
{
switch (alterTableCmd->subtype)
{
@ -268,7 +312,7 @@ AppendAlterTableCmd(StringInfo buf, AlterTableCmd *alterTableCmd)
*/
if (ConstrTypeCitusCanDefaultName(constraint->contype))
{
AppendAlterTableCmdAddConstraint(buf, constraint);
AppendAlterTableCmdAddConstraint(buf, constraint, stmt);
break;
}
}

View File

@ -408,6 +408,7 @@ extern void RenamePolicyEventExtendNames(RenameStmt *stmt, const char *schemaNam
extern void DropPolicyEventExtendNames(DropStmt *stmt, const char *schemaName, uint64
shardId);
extern void AddRangeTableEntryToQueryCompat(ParseState *parseState, Relation relation);
/* rename.c - forward declarations*/
extern List * PreprocessRenameStmt(Node *renameStmt, const char *renameCommand,

View File

@ -432,10 +432,6 @@ SELECT create_distributed_table('products', 'product_no');
ALTER TABLE products ADD CONSTRAINT unn_1 UNIQUE(product_no, price), ADD CONSTRAINT unn_2 UNIQUE(product_no, name);
ERROR: cannot execute ADD CONSTRAINT command with other subcommands
HINT: You can issue each subcommand separately
-- Tests for constraints without name
-- Commands below should error out since constraints do not have the name
ALTER TABLE products ADD CHECK(product_no <> 0);
ERROR: cannot create constraint without a name on a distributed table
-- ... with names, we can add/drop the constraints just fine
ALTER TABLE products ADD CONSTRAINT nonzero_product_no CHECK(product_no <> 0);
ALTER TABLE products ADD CONSTRAINT uniq_product_no EXCLUDE USING btree (product_no with =);

View File

@ -230,6 +230,56 @@ SELECT conname, tgfoid::regproc, tgtype, tgdeferrable, tginitdeferred
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_name_product_no_excl;
-- Check "ADD CHECK"
ALTER TABLE AT_AddConstNoName.products ADD CHECK (product_no > 0 AND price > 0);
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_check
(1 row)
\c - - :public_worker_1_host :worker_1_port
SELECT con.conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname = 'products_5410000';
conname
---------------------------------------------------------------------
products_check_5410000
(1 row)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_check;
-- Check "ADD CHECK ... NOINHERIT"
ALTER TABLE AT_AddConstNoName.products ADD CHECK (product_no > 0 AND price > 0) NO INHERIT;
SELECT con.conname, con.connoinherit
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 | connoinherit
---------------------------------------------------------------------
products_check | t
(1 row)
\c - - :public_worker_1_host :worker_1_port
SELECT con.conname, connoinherit
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 | connoinherit
---------------------------------------------------------------------
products_check_5410000 | t
(1 row)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_check;
DROP TABLE AT_AddConstNoName.products;
-- Check "ADD PRIMARY KEY" with reference table
CREATE TABLE AT_AddConstNoName.products_ref (
@ -303,6 +353,22 @@ SELECT con.conname
products_ref_product_no_excl2
(1 row)
ALTER TABLE AT_AddConstNoName.products_ref DROP CONSTRAINT products_ref_product_no_excl2;
-- Check that name collisions are handled for CHECK
ALTER TABLE AT_AddConstNoName.products_ref_3 ADD CONSTRAINT products_ref_check CHECK (product_no > 0);
ALTER TABLE AT_AddConstNoName.products_ref_2 ADD CONSTRAINT products_ref_check1 CHECK (product_no > 0);
ALTER TABLE AT_AddConstNoName.products_ref ADD CHECK (product_no > 0);
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_check2
(1 row)
ALTER TABLE AT_AddConstNoName.products_ref DROP CONSTRAINT products_ref_check2;
DROP TABLE AT_AddConstNoName.products_ref;
-- Check "ADD PRIMARY KEY" with max table name (63 chars)
CREATE TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonger (
@ -444,6 +510,49 @@ SELECT con.conname
---------------------------------------------------------------------
(0 rows)
-- Check "ADD CHECK" with max table name (63 chars)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon ADD CHECK (product_no > 0);
-- 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
---------------------------------------------------------------------
verylonglonglonglonglonglonglonglonglonglonglonglonglongl_check
(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_d943e063_5410006
verylonglonglonglonglonglonglonglonglonglonglo_d943e063_5410007
verylonglonglonglonglonglonglonglonglonglonglo_d943e063_5410008
verylonglonglonglonglonglonglonglonglonglonglo_d943e063_5410009
verylonglonglonglonglonglonglonglonglonglonglonglonglongl_check
(5 rows)
-- CHECK constraint can be deleted via the coordinator
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon DROP CONSTRAINT verylonglonglonglonglonglonglonglonglonglonglonglonglongl_check;
\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
@ -539,6 +648,40 @@ SELECT con.conname
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.dist_partitioned_table DROP CONSTRAINT dist_partitioned_table_partition_col_key;
-- Check "ADD CHECK"
SET client_min_messages TO DEBUG1;
ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD CHECK(dist_col >= another_col);
DEBUG: the constraint name on the shards of the partition is too long, switching to sequential and local execution mode to prevent self deadlocks: longlonglonglonglonglonglonglonglonglonglonglo_537570f5_5_check
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_check
(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
---------------------------------------------------------------------
dist_partitioned_table_check
dist_partitioned_table_check
dist_partitioned_table_check
dist_partitioned_table_check
dist_partitioned_table_check
(5 rows)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.dist_partitioned_table DROP CONSTRAINT dist_partitioned_table_check;
\c - - :public_worker_1_host :worker_1_port
SELECT con.conname
FROM pg_catalog.pg_constraint con
@ -599,6 +742,30 @@ BEGIN;
ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD UNIQUE(partition_col);
ROLLBACK;
-- Check "ADD CHECK"
\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 CHECK(dist_col > another_col);
ERROR: The constraint name (longlonglonglonglonglonglonglonglonglonglonglo_537570f5_5_check) 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 CHECK(dist_col > another_col);
ROLLBACK;
DROP TABLE AT_AddConstNoName.dist_partitioned_table;
-- Test with Citus Local Tables
-- Test "ADD PRIMARY KEY"
@ -735,6 +902,48 @@ SELECT con.conname
(5 rows)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.citus_local_table DROP CONSTRAINT citus_local_table_id_excl;
-- Check "ADD CHECK"
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.citus_local_table ADD CHECK(id > 100);
-- Check the CHECK constraint is created for the local table and its shard
SELECT con.conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC;
conname
---------------------------------------------------------------------
citus_local_table_check
(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_check
(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_check
citus_local_table_check_5410023
citus_local_table_check_5410024
citus_local_table_check_5410025
citus_local_table_check_5410026
(5 rows)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.citus_local_table DROP CONSTRAINT citus_local_table_check;
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);
@ -829,6 +1038,51 @@ ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table DROP CONSTRAINT citu
-- Check "ADD EXCLUDE" errors out for partitioned table since the postgres does not allow it
ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD EXCLUDE(partition_col WITH =);
ERROR: exclusion constraints are not supported on partitioned tables
-- Check "ADD CHECK"
SET client_min_messages TO DEBUG1;
ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD CHECK (dist_col > 0);
DEBUG: the constraint name on the shards of the partition is too long, switching to sequential and local execution mode to prevent self deadlocks: longlonglonglonglonglonglonglonglonglonglonglo_537570f5_5_check
DEBUG: verifying table "longlonglonglonglonglonglonglonglonglonglonglonglonglonglongabc"
DEBUG: verifying 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_check
(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
---------------------------------------------------------------------
citus_local_partitioned_table_check
citus_local_partitioned_table_check
citus_local_partitioned_table_check
citus_local_partitioned_table_check
citus_local_partitioned_table_check
(5 rows)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table DROP CONSTRAINT citus_local_partitioned_table_check;
\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)
\c - - :master_host :master_port
SELECT 1 FROM master_remove_node('localhost', :master_port);
?column?
---------------------------------------------------------------------
@ -933,6 +1187,36 @@ SELECT con.conname
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName."2nd table" DROP CONSTRAINT "2nd table_2nd id_excl";
-- Check "ADD CHECK"
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName."2nd table" ADD CHECK ("2nd id" > 0 );
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_check
(1 row)
\c - - :public_worker_1_host :worker_1_port
SELECT con.conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname LIKE '2nd table%' ORDER BY con.conname ASC;
conname
---------------------------------------------------------------------
2nd table_check
2nd table_check_5410042
2nd table_check_5410043
2nd table_check_5410044
2nd table_check_5410045
(5 rows)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName."2nd table" DROP CONSTRAINT "2nd table_check";
DROP EXTENSION btree_gist;
DROP SCHEMA AT_AddConstNoName CASCADE;
NOTICE: drop cascades to 6 other objects

View File

@ -67,9 +67,6 @@ SELECT create_distributed_table('name_lengths', 'col1', 'hash');
ALTER TABLE name_lengths ADD COLUMN float_col_12345678901234567890123456789012345678901234567890 FLOAT;
ALTER TABLE name_lengths ADD COLUMN date_col_12345678901234567890123456789012345678901234567890 DATE;
ALTER TABLE name_lengths ADD COLUMN int_col_12345678901234567890123456789012345678901234567890 INTEGER DEFAULT 1;
-- Placeholders for unsupported ALTER TABLE to add constraints with implicit names that are likely too long
ALTER TABLE name_lengths ADD CHECK (date_col_12345678901234567890123456789012345678901234567890 > '2014-01-01'::date);
ERROR: cannot create constraint without a name on a distributed table
\c - - :public_worker_1_host :worker_1_port
SELECT "Column", "Type", "Modifiers" FROM table_desc WHERE relid='public.name_lengths_225002'::regclass ORDER BY 1 DESC, 2 DESC;
Column | Type | Modifiers

View File

@ -376,10 +376,6 @@ SELECT create_distributed_table('products', 'product_no');
-- Should error out since add constraint is not the single subcommand
ALTER TABLE products ADD CONSTRAINT unn_1 UNIQUE(product_no, price), ADD CONSTRAINT unn_2 UNIQUE(product_no, name);
-- Tests for constraints without name
-- Commands below should error out since constraints do not have the name
ALTER TABLE products ADD CHECK(product_no <> 0);
-- ... with names, we can add/drop the constraints just fine
ALTER TABLE products ADD CONSTRAINT nonzero_product_no CHECK(product_no <> 0);
ALTER TABLE products ADD CONSTRAINT uniq_product_no EXCLUDE USING btree (product_no with =);

View File

@ -184,6 +184,43 @@ SELECT conname, tgfoid::regproc, tgtype, tgdeferrable, tginitdeferred
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_name_product_no_excl;
-- Check "ADD CHECK"
ALTER TABLE AT_AddConstNoName.products ADD CHECK (product_no > 0 AND price > 0);
SELECT con.conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname = 'products';
\c - - :public_worker_1_host :worker_1_port
SELECT con.conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname = 'products_5410000';
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.products DROP CONSTRAINT products_check;
-- Check "ADD CHECK ... NOINHERIT"
ALTER TABLE AT_AddConstNoName.products ADD CHECK (product_no > 0 AND price > 0) NO INHERIT;
SELECT con.conname, con.connoinherit
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname = 'products';
\c - - :public_worker_1_host :worker_1_port
SELECT con.conname, connoinherit
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_check;
DROP TABLE AT_AddConstNoName.products;
-- Check "ADD PRIMARY KEY" with reference table
@ -245,6 +282,21 @@ SELECT con.conname
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_product_no_excl2;
-- Check that name collisions are handled for CHECK
ALTER TABLE AT_AddConstNoName.products_ref_3 ADD CONSTRAINT products_ref_check CHECK (product_no > 0);
ALTER TABLE AT_AddConstNoName.products_ref_2 ADD CONSTRAINT products_ref_check1 CHECK (product_no > 0);
ALTER TABLE AT_AddConstNoName.products_ref ADD CHECK (product_no > 0);
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_check2;
DROP TABLE AT_AddConstNoName.products_ref;
-- Check "ADD PRIMARY KEY" with max table name (63 chars)
@ -337,6 +389,35 @@ SELECT con.conname
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon DROP CONSTRAINT verylonglonglonglonglonglonglonglonglonglonglon_product_no_excl;
\c - - :public_worker_1_host :worker_1_port
SELECT con.conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname LIKE 'very%';
-- Check "ADD CHECK" with max table name (63 chars)
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon ADD CHECK (product_no > 0);
-- 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;
-- CHECK constraint can be deleted via the coordinator
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglon DROP CONSTRAINT verylonglonglonglonglonglonglonglonglonglonglonglonglongl_check;
\c - - :public_worker_1_host :worker_1_port
SELECT con.conname
FROM pg_catalog.pg_constraint con
@ -402,6 +483,27 @@ SELECT con.conname
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.dist_partitioned_table DROP CONSTRAINT dist_partitioned_table_partition_col_key;
-- Check "ADD CHECK"
SET client_min_messages TO DEBUG1;
ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD CHECK(dist_col >= another_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_check;
\c - - :public_worker_1_host :worker_1_port
SELECT con.conname
FROM pg_catalog.pg_constraint con
@ -438,6 +540,19 @@ BEGIN;
ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD UNIQUE(partition_col);
ROLLBACK;
-- Check "ADD CHECK"
\c - - :master_host :master_port
BEGIN;
SELECT count(*) FROM AT_AddConstNoName.dist_partitioned_table;
ALTER TABLE AT_AddConstNoName.dist_partitioned_table ADD CHECK(dist_col > another_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 CHECK(dist_col > another_col);
ROLLBACK;
DROP TABLE AT_AddConstNoName.dist_partitioned_table;
-- Test with Citus Local Tables
@ -524,6 +639,35 @@ SELECT con.conname
WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC;
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.citus_local_table DROP CONSTRAINT citus_local_table_id_excl;
-- Check "ADD CHECK"
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.citus_local_table ADD CHECK(id > 100);
-- Check the CHECK constraint is created for the local table and its shard
SELECT con.conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC;
SELECT con.conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC;
\c - - :public_worker_1_host :worker_1_port
SELECT con.conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname LIKE 'citus_local_table%' ORDER BY con.conname ASC;
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName.citus_local_table DROP CONSTRAINT citus_local_table_check;
DROP TABLE AT_AddConstNoName.citus_local_table;
-- Test with partitioned citus local table
@ -587,6 +731,35 @@ ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table DROP CONSTRAINT citu
-- Check "ADD EXCLUDE" errors out for partitioned table since the postgres does not allow it
ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD EXCLUDE(partition_col WITH =);
-- Check "ADD CHECK"
SET client_min_messages TO DEBUG1;
ALTER TABLE AT_AddConstNoName.citus_local_partitioned_table ADD CHECK (dist_col > 0);
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_check;
\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
SELECT 1 FROM master_remove_node('localhost', :master_port);
-- Test with unusual table and column names
@ -652,5 +825,25 @@ SELECT con.conname
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName."2nd table" DROP CONSTRAINT "2nd table_2nd id_excl";
-- Check "ADD CHECK"
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName."2nd table" ADD CHECK ("2nd id" > 0 );
SELECT con.conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname = '2nd table';
\c - - :public_worker_1_host :worker_1_port
SELECT con.conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname LIKE '2nd table%' ORDER BY con.conname ASC;
\c - - :master_host :master_port
ALTER TABLE AT_AddConstNoName."2nd table" DROP CONSTRAINT "2nd table_check";
DROP EXTENSION btree_gist;
DROP SCHEMA AT_AddConstNoName CASCADE;

View File

@ -45,9 +45,6 @@ ALTER TABLE name_lengths ADD COLUMN float_col_1234567890123456789012345678901234
ALTER TABLE name_lengths ADD COLUMN date_col_12345678901234567890123456789012345678901234567890 DATE;
ALTER TABLE name_lengths ADD COLUMN int_col_12345678901234567890123456789012345678901234567890 INTEGER DEFAULT 1;
-- Placeholders for unsupported ALTER TABLE to add constraints with implicit names that are likely too long
ALTER TABLE name_lengths ADD CHECK (date_col_12345678901234567890123456789012345678901234567890 > '2014-01-01'::date);
\c - - :public_worker_1_host :worker_1_port
SELECT "Column", "Type", "Modifiers" FROM table_desc WHERE relid='public.name_lengths_225002'::regclass ORDER BY 1 DESC, 2 DESC;
\c - - :master_host :master_port