Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitaf20e2d

Browse files
committed
Fix ALTER TABLE code to update domain constraints when needed.
It's possible for dropping a column, or altering its type, to requirechanges in domain CHECK constraint expressions; but the code waspreviously only expecting to find dependent table CHECK constraints.Make the necessary adjustments.This is a fairly old oversight, but it's a lot easier to encounterthe problem in the context of domains over composite types than itwas before. Given the lack of field complaints, I'm not going tobother with a back-patch, though I'd be willing to reconsider thatdecision if someone does complain.Patch by me, reviewed by Michael PaquierDiscussion:https://postgr.es/m/30656.1509128130@sss.pgh.pa.us
1 parent387ec70 commitaf20e2d

File tree

5 files changed

+186
-25
lines changed

5 files changed

+186
-25
lines changed

‎src/backend/commands/tablecmds.c

Lines changed: 82 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,8 @@ static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
425425
char*cmd,List**wqueue,LOCKMODElockmode,
426426
boolrewrite);
427427
staticvoidRebuildConstraintComment(AlteredTableInfo*tab,intpass,
428-
Oidobjid,Relationrel,char*conname);
428+
Oidobjid,Relationrel,List*domname,
429+
char*conname);
429430
staticvoidTryReuseIndex(OidoldId,IndexStmt*stmt);
430431
staticvoidTryReuseForeignKey(OidoldId,Constraint*con);
431432
staticvoidchange_owner_fix_column_acls(OidrelationOid,
@@ -3319,6 +3320,7 @@ AlterTableGetLockLevel(List *cmds)
33193320
caseAT_ProcessedConstraint:/* becomes AT_AddConstraint */
33203321
caseAT_AddConstraintRecurse:/* becomes AT_AddConstraint */
33213322
caseAT_ReAddConstraint:/* becomes AT_AddConstraint */
3323+
caseAT_ReAddDomainConstraint:/* becomes AT_AddConstraint */
33223324
if (IsA(cmd->def,Constraint))
33233325
{
33243326
Constraint*con= (Constraint*)cmd->def;
@@ -3819,7 +3821,9 @@ ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
38193821
rel=relation_open(tab->relid,NoLock);
38203822

38213823
foreach(lcmd,subcmds)
3822-
ATExecCmd(wqueue,tab,rel, (AlterTableCmd*)lfirst(lcmd),lockmode);
3824+
ATExecCmd(wqueue,tab,rel,
3825+
castNode(AlterTableCmd,lfirst(lcmd)),
3826+
lockmode);
38233827

38243828
/*
38253829
* After the ALTER TYPE pass, do cleanup work (this is not done in
@@ -3936,6 +3940,13 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
39363940
ATExecAddConstraint(wqueue,tab,rel, (Constraint*)cmd->def,
39373941
true, true,lockmode);
39383942
break;
3943+
caseAT_ReAddDomainConstraint:/* Re-add pre-existing domain check
3944+
* constraint */
3945+
address=
3946+
AlterDomainAddConstraint(((AlterDomainStmt*)cmd->def)->typeName,
3947+
((AlterDomainStmt*)cmd->def)->def,
3948+
NULL);
3949+
break;
39393950
caseAT_ReAddComment:/* Re-add existing comment */
39403951
address=CommentObject((CommentStmt*)cmd->def);
39413952
break;
@@ -9616,7 +9627,15 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
96169627
if (!HeapTupleIsValid(tup))/* should not happen */
96179628
elog(ERROR,"cache lookup failed for constraint %u",oldId);
96189629
con= (Form_pg_constraint)GETSTRUCT(tup);
9619-
relid=con->conrelid;
9630+
if (OidIsValid(con->conrelid))
9631+
relid=con->conrelid;
9632+
else
9633+
{
9634+
/* must be a domain constraint */
9635+
relid=get_typ_typrelid(getBaseType(con->contypid));
9636+
if (!OidIsValid(relid))
9637+
elog(ERROR,"could not identify relation associated with constraint %u",oldId);
9638+
}
96209639
confrelid=con->confrelid;
96219640
conislocal=con->conislocal;
96229641
ReleaseSysCache(tup);
@@ -9753,7 +9772,7 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
97539772

97549773
foreach(lcmd,stmt->cmds)
97559774
{
9756-
AlterTableCmd*cmd= (AlterTableCmd*)lfirst(lcmd);
9775+
AlterTableCmd*cmd=castNode(AlterTableCmd,lfirst(lcmd));
97579776

97589777
if (cmd->subtype==AT_AddIndex)
97599778
{
@@ -9777,13 +9796,14 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
97779796
RebuildConstraintComment(tab,
97789797
AT_PASS_OLD_INDEX,
97799798
oldId,
9780-
rel,indstmt->idxname);
9799+
rel,
9800+
NIL,
9801+
indstmt->idxname);
97819802
}
97829803
elseif (cmd->subtype==AT_AddConstraint)
97839804
{
9784-
Constraint*con;
9805+
Constraint*con=castNode(Constraint,cmd->def);
97859806

9786-
con=castNode(Constraint,cmd->def);
97879807
con->old_pktable_oid=refRelId;
97889808
/* rewriting neither side of a FK */
97899809
if (con->contype==CONSTR_FOREIGN&&
@@ -9797,13 +9817,41 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
97979817
RebuildConstraintComment(tab,
97989818
AT_PASS_OLD_CONSTR,
97999819
oldId,
9800-
rel,con->conname);
9820+
rel,
9821+
NIL,
9822+
con->conname);
98019823
}
98029824
else
98039825
elog(ERROR,"unexpected statement subtype: %d",
98049826
(int)cmd->subtype);
98059827
}
98069828
}
9829+
elseif (IsA(stm,AlterDomainStmt))
9830+
{
9831+
AlterDomainStmt*stmt= (AlterDomainStmt*)stm;
9832+
9833+
if (stmt->subtype=='C')/* ADD CONSTRAINT */
9834+
{
9835+
Constraint*con=castNode(Constraint,stmt->def);
9836+
AlterTableCmd*cmd=makeNode(AlterTableCmd);
9837+
9838+
cmd->subtype=AT_ReAddDomainConstraint;
9839+
cmd->def= (Node*)stmt;
9840+
tab->subcmds[AT_PASS_OLD_CONSTR]=
9841+
lappend(tab->subcmds[AT_PASS_OLD_CONSTR],cmd);
9842+
9843+
/* recreate any comment on the constraint */
9844+
RebuildConstraintComment(tab,
9845+
AT_PASS_OLD_CONSTR,
9846+
oldId,
9847+
NULL,
9848+
stmt->typeName,
9849+
con->conname);
9850+
}
9851+
else
9852+
elog(ERROR,"unexpected statement subtype: %d",
9853+
(int)stmt->subtype);
9854+
}
98079855
else
98089856
elog(ERROR,"unexpected statement type: %d",
98099857
(int)nodeTag(stm));
@@ -9813,12 +9861,19 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
98139861
}
98149862

98159863
/*
9816-
* Subroutine for ATPostAlterTypeParse() to recreate a comment entry for
9817-
* a constraint that is being re-added.
9864+
* Subroutine for ATPostAlterTypeParse() to recreate any existing comment
9865+
* for a table or domain constraint that is being rebuilt.
9866+
*
9867+
* objid is the OID of the constraint.
9868+
* Pass "rel" for a table constraint, or "domname" (domain's qualified name
9869+
* as a string list) for a domain constraint.
9870+
* (We could dig that info, as well as the conname, out of the pg_constraint
9871+
* entry; but callers already have them so might as well pass them.)
98189872
*/
98199873
staticvoid
98209874
RebuildConstraintComment(AlteredTableInfo*tab,intpass,Oidobjid,
9821-
Relationrel,char*conname)
9875+
Relationrel,List*domname,
9876+
char*conname)
98229877
{
98239878
CommentStmt*cmd;
98249879
char*comment_str;
@@ -9829,12 +9884,23 @@ RebuildConstraintComment(AlteredTableInfo *tab, int pass, Oid objid,
98299884
if (comment_str==NULL)
98309885
return;
98319886

9832-
/* Build node CommentStmt */
9887+
/* BuildCommentStmtnode, copying all input data for safety */
98339888
cmd=makeNode(CommentStmt);
9834-
cmd->objtype=OBJECT_TABCONSTRAINT;
9835-
cmd->object= (Node*)list_make3(makeString(get_namespace_name(RelationGetNamespace(rel))),
9836-
makeString(pstrdup(RelationGetRelationName(rel))),
9837-
makeString(pstrdup(conname)));
9889+
if (rel)
9890+
{
9891+
cmd->objtype=OBJECT_TABCONSTRAINT;
9892+
cmd->object= (Node*)
9893+
list_make3(makeString(get_namespace_name(RelationGetNamespace(rel))),
9894+
makeString(pstrdup(RelationGetRelationName(rel))),
9895+
makeString(pstrdup(conname)));
9896+
}
9897+
else
9898+
{
9899+
cmd->objtype=OBJECT_DOMCONSTRAINT;
9900+
cmd->object= (Node*)
9901+
list_make2(makeTypeNameFromNameList(copyObject(domname)),
9902+
makeString(pstrdup(conname)));
9903+
}
98389904
cmd->comment=comment_str;
98399905

98409906
/* Append it to list of commands */

‎src/backend/utils/adt/ruleutils.c

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ static char *generate_function_name(Oid funcid, int nargs,
460460
boolhas_variadic,bool*use_variadic_p,
461461
ParseExprKindspecial_exprkind);
462462
staticchar*generate_operator_name(Oidoperid,Oidarg1,Oidarg2);
463+
staticchar*generate_qualified_type_name(Oidtypid);
463464
statictext*string_to_text(char*str);
464465
staticchar*flatten_reloptions(Oidrelid);
465466

@@ -1867,15 +1868,27 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
18671868

18681869
if (fullCommand)
18691870
{
1870-
/*
1871-
* Currently, callers want ALTER TABLE (without ONLY) for CHECK
1872-
* constraints, and other types of constraints don't inherit anyway so
1873-
* it doesn't matter whether we say ONLY or not. Someday we might
1874-
* need to let callers specify whether to put ONLY in the command.
1875-
*/
1876-
appendStringInfo(&buf,"ALTER TABLE %s ADD CONSTRAINT %s ",
1877-
generate_qualified_relation_name(conForm->conrelid),
1878-
quote_identifier(NameStr(conForm->conname)));
1871+
if (OidIsValid(conForm->conrelid))
1872+
{
1873+
/*
1874+
* Currently, callers want ALTER TABLE (without ONLY) for CHECK
1875+
* constraints, and other types of constraints don't inherit
1876+
* anyway so it doesn't matter whether we say ONLY or not. Someday
1877+
* we might need to let callers specify whether to put ONLY in the
1878+
* command.
1879+
*/
1880+
appendStringInfo(&buf,"ALTER TABLE %s ADD CONSTRAINT %s ",
1881+
generate_qualified_relation_name(conForm->conrelid),
1882+
quote_identifier(NameStr(conForm->conname)));
1883+
}
1884+
else
1885+
{
1886+
/* Must be a domain constraint */
1887+
Assert(OidIsValid(conForm->contypid));
1888+
appendStringInfo(&buf,"ALTER DOMAIN %s ADD CONSTRAINT %s ",
1889+
generate_qualified_type_name(conForm->contypid),
1890+
quote_identifier(NameStr(conForm->conname)));
1891+
}
18791892
}
18801893

18811894
switch (conForm->contype)
@@ -10778,6 +10791,42 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2)
1077810791
returnbuf.data;
1077910792
}
1078010793

10794+
/*
10795+
* generate_qualified_type_name
10796+
*Compute the name to display for a type specified by OID
10797+
*
10798+
* This is different from format_type_be() in that we unconditionally
10799+
* schema-qualify the name. That also means no special syntax for
10800+
* SQL-standard type names ... although in current usage, this should
10801+
* only get used for domains, so such cases wouldn't occur anyway.
10802+
*/
10803+
staticchar*
10804+
generate_qualified_type_name(Oidtypid)
10805+
{
10806+
HeapTupletp;
10807+
Form_pg_typetyptup;
10808+
char*typname;
10809+
char*nspname;
10810+
char*result;
10811+
10812+
tp=SearchSysCache1(TYPEOID,ObjectIdGetDatum(typid));
10813+
if (!HeapTupleIsValid(tp))
10814+
elog(ERROR,"cache lookup failed for type %u",typid);
10815+
typtup= (Form_pg_type)GETSTRUCT(tp);
10816+
typname=NameStr(typtup->typname);
10817+
10818+
nspname=get_namespace_name(typtup->typnamespace);
10819+
if (!nspname)
10820+
elog(ERROR,"cache lookup failed for namespace %u",
10821+
typtup->typnamespace);
10822+
10823+
result=quote_qualified_identifier(nspname,typname);
10824+
10825+
ReleaseSysCache(tp);
10826+
10827+
returnresult;
10828+
}
10829+
1078110830
/*
1078210831
* generate_collation_name
1078310832
*Compute the name to display for a collation specified by OID

‎src/include/nodes/parsenodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,6 +1713,7 @@ typedef enum AlterTableType
17131713
AT_AddConstraint,/* add constraint */
17141714
AT_AddConstraintRecurse,/* internal to commands/tablecmds.c */
17151715
AT_ReAddConstraint,/* internal to commands/tablecmds.c */
1716+
AT_ReAddDomainConstraint,/* internal to commands/tablecmds.c */
17161717
AT_AlterConstraint,/* alter constraint */
17171718
AT_ValidateConstraint,/* validate constraint */
17181719
AT_ValidateConstraintRecurse,/* internal to commands/tablecmds.c */

‎src/test/regress/expected/domain.out

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,31 @@ Rules:
284284
WHERE (dcomptable.d1).i > 0::double precision
285285

286286
drop table dcomptable;
287+
drop type comptype cascade;
288+
NOTICE: drop cascades to type dcomptype
289+
-- check altering and dropping columns used by domain constraints
290+
create type comptype as (r float8, i float8);
291+
create domain dcomptype as comptype;
292+
alter domain dcomptype add constraint c1 check ((value).r > 0);
293+
comment on constraint c1 on domain dcomptype is 'random commentary';
294+
select row(0,1)::dcomptype; -- fail
295+
ERROR: value for domain dcomptype violates check constraint "c1"
296+
alter type comptype alter attribute r type varchar; -- fail
297+
ERROR: operator does not exist: character varying > double precision
298+
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
299+
alter type comptype alter attribute r type bigint;
300+
alter type comptype drop attribute r; -- fail
301+
ERROR: cannot drop composite type comptype column r because other objects depend on it
302+
DETAIL: constraint c1 depends on composite type comptype column r
303+
HINT: Use DROP ... CASCADE to drop the dependent objects too.
304+
alter type comptype drop attribute i;
305+
select conname, obj_description(oid, 'pg_constraint') from pg_constraint
306+
where contypid = 'dcomptype'::regtype; -- check comment is still there
307+
conname | obj_description
308+
---------+-------------------
309+
c1 | random commentary
310+
(1 row)
311+
287312
drop type comptype cascade;
288313
NOTICE: drop cascades to type dcomptype
289314
-- Test domains over arrays of composite

‎src/test/regress/sql/domain.sql

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,26 @@ drop table dcomptable;
159159
droptype comptype cascade;
160160

161161

162+
-- check altering and dropping columns used by domain constraints
163+
createtypecomptypeas (r float8, i float8);
164+
createdomaindcomptypeas comptype;
165+
alterdomain dcomptype addconstraint c1check ((value).r>0);
166+
comment on constraint c1 on domain dcomptype is'random commentary';
167+
168+
select row(0,1)::dcomptype;-- fail
169+
170+
altertype comptype alter attribute r typevarchar;-- fail
171+
altertype comptype alter attribute r typebigint;
172+
173+
altertype comptype drop attribute r;-- fail
174+
altertype comptype drop attribute i;
175+
176+
select conname, obj_description(oid,'pg_constraint')from pg_constraint
177+
where contypid='dcomptype'::regtype;-- check comment is still there
178+
179+
droptype comptype cascade;
180+
181+
162182
-- Test domains over arrays of composite
163183

164184
createtypecomptypeas (r float8, i float8);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp