aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/tablecmds.c98
-rw-r--r--src/backend/utils/adt/ruleutils.c67
-rw-r--r--src/include/nodes/parsenodes.h1
-rw-r--r--src/test/regress/expected/domain.out25
-rw-r--r--src/test/regress/sql/domain.sql20
5 files changed, 186 insertions, 25 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3ab808715b9..c902293741c 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -425,7 +425,8 @@ static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
char *cmd, List **wqueue, LOCKMODE lockmode,
bool rewrite);
static void RebuildConstraintComment(AlteredTableInfo *tab, int pass,
- Oid objid, Relation rel, char *conname);
+ Oid objid, Relation rel, List *domname,
+ char *conname);
static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
static void TryReuseForeignKey(Oid oldId, Constraint *con);
static void change_owner_fix_column_acls(Oid relationOid,
@@ -3319,6 +3320,7 @@ AlterTableGetLockLevel(List *cmds)
case AT_ProcessedConstraint: /* becomes AT_AddConstraint */
case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
case AT_ReAddConstraint: /* becomes AT_AddConstraint */
+ case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
if (IsA(cmd->def, Constraint))
{
Constraint *con = (Constraint *) cmd->def;
@@ -3819,7 +3821,9 @@ ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
rel = relation_open(tab->relid, NoLock);
foreach(lcmd, subcmds)
- ATExecCmd(wqueue, tab, rel, (AlterTableCmd *) lfirst(lcmd), lockmode);
+ ATExecCmd(wqueue, tab, rel,
+ castNode(AlterTableCmd, lfirst(lcmd)),
+ lockmode);
/*
* After the ALTER TYPE pass, do cleanup work (this is not done in
@@ -3936,6 +3940,13 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
ATExecAddConstraint(wqueue, tab, rel, (Constraint *) cmd->def,
true, true, lockmode);
break;
+ case AT_ReAddDomainConstraint: /* Re-add pre-existing domain check
+ * constraint */
+ address =
+ AlterDomainAddConstraint(((AlterDomainStmt *) cmd->def)->typeName,
+ ((AlterDomainStmt *) cmd->def)->def,
+ NULL);
+ break;
case AT_ReAddComment: /* Re-add existing comment */
address = CommentObject((CommentStmt *) cmd->def);
break;
@@ -9616,7 +9627,15 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for constraint %u", oldId);
con = (Form_pg_constraint) GETSTRUCT(tup);
- relid = con->conrelid;
+ if (OidIsValid(con->conrelid))
+ relid = con->conrelid;
+ else
+ {
+ /* must be a domain constraint */
+ relid = get_typ_typrelid(getBaseType(con->contypid));
+ if (!OidIsValid(relid))
+ elog(ERROR, "could not identify relation associated with constraint %u", oldId);
+ }
confrelid = con->confrelid;
conislocal = con->conislocal;
ReleaseSysCache(tup);
@@ -9753,7 +9772,7 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
foreach(lcmd, stmt->cmds)
{
- AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
+ AlterTableCmd *cmd = castNode(AlterTableCmd, lfirst(lcmd));
if (cmd->subtype == AT_AddIndex)
{
@@ -9777,13 +9796,14 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
RebuildConstraintComment(tab,
AT_PASS_OLD_INDEX,
oldId,
- rel, indstmt->idxname);
+ rel,
+ NIL,
+ indstmt->idxname);
}
else if (cmd->subtype == AT_AddConstraint)
{
- Constraint *con;
+ Constraint *con = castNode(Constraint, cmd->def);
- con = castNode(Constraint, cmd->def);
con->old_pktable_oid = refRelId;
/* rewriting neither side of a FK */
if (con->contype == CONSTR_FOREIGN &&
@@ -9797,13 +9817,41 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
RebuildConstraintComment(tab,
AT_PASS_OLD_CONSTR,
oldId,
- rel, con->conname);
+ rel,
+ NIL,
+ con->conname);
}
else
elog(ERROR, "unexpected statement subtype: %d",
(int) cmd->subtype);
}
}
+ else if (IsA(stm, AlterDomainStmt))
+ {
+ AlterDomainStmt *stmt = (AlterDomainStmt *) stm;
+
+ if (stmt->subtype == 'C') /* ADD CONSTRAINT */
+ {
+ Constraint *con = castNode(Constraint, stmt->def);
+ AlterTableCmd *cmd = makeNode(AlterTableCmd);
+
+ cmd->subtype = AT_ReAddDomainConstraint;
+ cmd->def = (Node *) stmt;
+ tab->subcmds[AT_PASS_OLD_CONSTR] =
+ lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
+
+ /* recreate any comment on the constraint */
+ RebuildConstraintComment(tab,
+ AT_PASS_OLD_CONSTR,
+ oldId,
+ NULL,
+ stmt->typeName,
+ con->conname);
+ }
+ else
+ elog(ERROR, "unexpected statement subtype: %d",
+ (int) stmt->subtype);
+ }
else
elog(ERROR, "unexpected statement type: %d",
(int) nodeTag(stm));
@@ -9813,12 +9861,19 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
}
/*
- * Subroutine for ATPostAlterTypeParse() to recreate a comment entry for
- * a constraint that is being re-added.
+ * Subroutine for ATPostAlterTypeParse() to recreate any existing comment
+ * for a table or domain constraint that is being rebuilt.
+ *
+ * objid is the OID of the constraint.
+ * Pass "rel" for a table constraint, or "domname" (domain's qualified name
+ * as a string list) for a domain constraint.
+ * (We could dig that info, as well as the conname, out of the pg_constraint
+ * entry; but callers already have them so might as well pass them.)
*/
static void
RebuildConstraintComment(AlteredTableInfo *tab, int pass, Oid objid,
- Relation rel, char *conname)
+ Relation rel, List *domname,
+ char *conname)
{
CommentStmt *cmd;
char *comment_str;
@@ -9829,12 +9884,23 @@ RebuildConstraintComment(AlteredTableInfo *tab, int pass, Oid objid,
if (comment_str == NULL)
return;
- /* Build node CommentStmt */
+ /* Build CommentStmt node, copying all input data for safety */
cmd = makeNode(CommentStmt);
- cmd->objtype = OBJECT_TABCONSTRAINT;
- cmd->object = (Node *) list_make3(makeString(get_namespace_name(RelationGetNamespace(rel))),
- makeString(pstrdup(RelationGetRelationName(rel))),
- makeString(pstrdup(conname)));
+ if (rel)
+ {
+ cmd->objtype = OBJECT_TABCONSTRAINT;
+ cmd->object = (Node *)
+ list_make3(makeString(get_namespace_name(RelationGetNamespace(rel))),
+ makeString(pstrdup(RelationGetRelationName(rel))),
+ makeString(pstrdup(conname)));
+ }
+ else
+ {
+ cmd->objtype = OBJECT_DOMCONSTRAINT;
+ cmd->object = (Node *)
+ list_make2(makeTypeNameFromNameList(copyObject(domname)),
+ makeString(pstrdup(conname)));
+ }
cmd->comment = comment_str;
/* Append it to list of commands */
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index b1e70a0d19e..cc6cec7877d 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -460,6 +460,7 @@ static char *generate_function_name(Oid funcid, int nargs,
bool has_variadic, bool *use_variadic_p,
ParseExprKind special_exprkind);
static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
+static char *generate_qualified_type_name(Oid typid);
static text *string_to_text(char *str);
static char *flatten_reloptions(Oid relid);
@@ -1867,15 +1868,27 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
if (fullCommand)
{
- /*
- * Currently, callers want ALTER TABLE (without ONLY) for CHECK
- * constraints, and other types of constraints don't inherit anyway so
- * it doesn't matter whether we say ONLY or not. Someday we might
- * need to let callers specify whether to put ONLY in the command.
- */
- appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
- generate_qualified_relation_name(conForm->conrelid),
- quote_identifier(NameStr(conForm->conname)));
+ if (OidIsValid(conForm->conrelid))
+ {
+ /*
+ * Currently, callers want ALTER TABLE (without ONLY) for CHECK
+ * constraints, and other types of constraints don't inherit
+ * anyway so it doesn't matter whether we say ONLY or not. Someday
+ * we might need to let callers specify whether to put ONLY in the
+ * command.
+ */
+ appendStringInfo(&buf, "ALTER TABLE %s ADD CONSTRAINT %s ",
+ generate_qualified_relation_name(conForm->conrelid),
+ quote_identifier(NameStr(conForm->conname)));
+ }
+ else
+ {
+ /* Must be a domain constraint */
+ Assert(OidIsValid(conForm->contypid));
+ appendStringInfo(&buf, "ALTER DOMAIN %s ADD CONSTRAINT %s ",
+ generate_qualified_type_name(conForm->contypid),
+ quote_identifier(NameStr(conForm->conname)));
+ }
}
switch (conForm->contype)
@@ -10779,6 +10792,42 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2)
}
/*
+ * generate_qualified_type_name
+ * Compute the name to display for a type specified by OID
+ *
+ * This is different from format_type_be() in that we unconditionally
+ * schema-qualify the name. That also means no special syntax for
+ * SQL-standard type names ... although in current usage, this should
+ * only get used for domains, so such cases wouldn't occur anyway.
+ */
+static char *
+generate_qualified_type_name(Oid typid)
+{
+ HeapTuple tp;
+ Form_pg_type typtup;
+ char *typname;
+ char *nspname;
+ char *result;
+
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for type %u", typid);
+ typtup = (Form_pg_type) GETSTRUCT(tp);
+ typname = NameStr(typtup->typname);
+
+ nspname = get_namespace_name(typtup->typnamespace);
+ if (!nspname)
+ elog(ERROR, "cache lookup failed for namespace %u",
+ typtup->typnamespace);
+
+ result = quote_qualified_identifier(nspname, typname);
+
+ ReleaseSysCache(tp);
+
+ return result;
+}
+
+/*
* generate_collation_name
* Compute the name to display for a collation specified by OID
*
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 732e5d67883..06a2b81fb5b 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1713,6 +1713,7 @@ typedef enum AlterTableType
AT_AddConstraint, /* add constraint */
AT_AddConstraintRecurse, /* internal to commands/tablecmds.c */
AT_ReAddConstraint, /* internal to commands/tablecmds.c */
+ AT_ReAddDomainConstraint, /* internal to commands/tablecmds.c */
AT_AlterConstraint, /* alter constraint */
AT_ValidateConstraint, /* validate constraint */
AT_ValidateConstraintRecurse, /* internal to commands/tablecmds.c */
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index f7f3948d431..f4eebb75cf2 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -286,6 +286,31 @@ Rules:
drop table dcomptable;
drop type comptype cascade;
NOTICE: drop cascades to type dcomptype
+-- check altering and dropping columns used by domain constraints
+create type comptype as (r float8, i float8);
+create domain dcomptype as comptype;
+alter domain dcomptype add constraint c1 check ((value).r > 0);
+comment on constraint c1 on domain dcomptype is 'random commentary';
+select row(0,1)::dcomptype; -- fail
+ERROR: value for domain dcomptype violates check constraint "c1"
+alter type comptype alter attribute r type varchar; -- fail
+ERROR: operator does not exist: character varying > double precision
+HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+alter type comptype alter attribute r type bigint;
+alter type comptype drop attribute r; -- fail
+ERROR: cannot drop composite type comptype column r because other objects depend on it
+DETAIL: constraint c1 depends on composite type comptype column r
+HINT: Use DROP ... CASCADE to drop the dependent objects too.
+alter type comptype drop attribute i;
+select conname, obj_description(oid, 'pg_constraint') from pg_constraint
+ where contypid = 'dcomptype'::regtype; -- check comment is still there
+ conname | obj_description
+---------+-------------------
+ c1 | random commentary
+(1 row)
+
+drop type comptype cascade;
+NOTICE: drop cascades to type dcomptype
-- Test domains over arrays of composite
create type comptype as (r float8, i float8);
create domain dcomptypea as comptype[];
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index 5201f008a1c..68da27de22b 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -159,6 +159,26 @@ drop table dcomptable;
drop type comptype cascade;
+-- check altering and dropping columns used by domain constraints
+create type comptype as (r float8, i float8);
+create domain dcomptype as comptype;
+alter domain dcomptype add constraint c1 check ((value).r > 0);
+comment on constraint c1 on domain dcomptype is 'random commentary';
+
+select row(0,1)::dcomptype; -- fail
+
+alter type comptype alter attribute r type varchar; -- fail
+alter type comptype alter attribute r type bigint;
+
+alter type comptype drop attribute r; -- fail
+alter type comptype drop attribute i;
+
+select conname, obj_description(oid, 'pg_constraint') from pg_constraint
+ where contypid = 'dcomptype'::regtype; -- check comment is still there
+
+drop type comptype cascade;
+
+
-- Test domains over arrays of composite
create type comptype as (r float8, i float8);