mirror of https://github.com/citusdata/citus.git
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
parent
a6ad4574f6
commit
28ed013a91
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 =);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 =);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue