Skip to content

Commit 3752e85

Browse files
committed
Determine the set of constraints applied to a domain at executor
startup, not in the parser; this allows ALTER DOMAIN to work correctly with domain constraint operations stored in rules. Rod Taylor; code review by Tom Lane.
1 parent 464598b commit 3752e85

File tree

24 files changed

+524
-339
lines changed

24 files changed

+524
-339
lines changed

src/backend/commands/copy.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.188 2003/01/10 22:03:27 petere Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.189 2003/02/03 21:15:43 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -853,7 +853,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
853853
}
854854
}
855855

856-
/* If it's a domain type, get info on domain constraints */
856+
/* If it's a domain type, set up to check domain constraints */
857857
if (get_typtype(attr[i]->atttypid) == 'd')
858858
{
859859
Param *prm;
@@ -863,25 +863,23 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
863863
* Easiest way to do this is to use parse_coerce.c to set up
864864
* an expression that checks the constraints. (At present,
865865
* the expression might contain a length-coercion-function call
866-
* and/or ConstraintTest nodes.) The bottom of the expression
866+
* and/or CoerceToDomain nodes.) The bottom of the expression
867867
* is a Param node so that we can fill in the actual datum during
868868
* the data input loop.
869869
*/
870870
prm = makeNode(Param);
871871
prm->paramkind = PARAM_EXEC;
872872
prm->paramid = 0;
873-
prm->paramtype = attr[i]->atttypid;
873+
prm->paramtype = getBaseType(attr[i]->atttypid);
874874

875-
node = coerce_type_constraints((Node *) prm, attr[i]->atttypid,
876-
COERCE_IMPLICIT_CAST);
875+
node = coerce_to_domain((Node *) prm,
876+
prm->paramtype,
877+
attr[i]->atttypid,
878+
COERCE_IMPLICIT_CAST);
877879

878-
/* check whether any constraints actually found */
879-
if (node != (Node *) prm)
880-
{
881-
constraintexprs[i] = ExecPrepareExpr((Expr *) node,
882-
estate);
883-
hasConstraints = true;
884-
}
880+
constraintexprs[i] = ExecPrepareExpr((Expr *) node,
881+
estate);
882+
hasConstraints = true;
885883
}
886884
}
887885

src/backend/commands/typecmds.c

Lines changed: 125 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.29 2003/01/08 22:06:23 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.30 2003/02/03 21:15:43 tgl Exp $
1212
*
1313
* DESCRIPTION
1414
* The "DefineFoo" routines take the parse tree and pick out the
@@ -46,8 +46,10 @@
4646
#include "commands/typecmds.h"
4747
#include "executor/executor.h"
4848
#include "miscadmin.h"
49+
#include "nodes/execnodes.h"
4950
#include "nodes/nodes.h"
5051
#include "optimizer/clauses.h"
52+
#include "optimizer/planmain.h"
5153
#include "optimizer/var.h"
5254
#include "parser/parse_coerce.h"
5355
#include "parser/parse_expr.h"
@@ -1555,7 +1557,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
15551557
char *ccsrc;
15561558
char *ccbin;
15571559
ParseState *pstate;
1558-
ConstraintTestValue *domVal;
1560+
CoerceToDomainValue *domVal;
15591561

15601562
/*
15611563
* Assign or validate constraint name
@@ -1582,13 +1584,13 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
15821584
pstate = make_parsestate(NULL);
15831585

15841586
/*
1585-
* Set up a ConstraintTestValue to represent the occurrence of VALUE
1587+
* Set up a CoerceToDomainValue to represent the occurrence of VALUE
15861588
* in the expression. Note that it will appear to have the type of the
15871589
* base type, not the domain. This seems correct since within the
15881590
* check expression, we should not assume the input value can be considered
15891591
* a member of the domain.
15901592
*/
1591-
domVal = makeNode(ConstraintTestValue);
1593+
domVal = makeNode(CoerceToDomainValue);
15921594
domVal->typeId = baseTypeOid;
15931595
domVal->typeMod = typMod;
15941596

@@ -1669,6 +1671,125 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
16691671
return ccbin;
16701672
}
16711673

1674+
/*
1675+
* GetDomainConstraints - get a list of the current constraints of domain
1676+
*
1677+
* Returns a possibly-empty list of DomainConstraintState nodes.
1678+
*
1679+
* This is called by the executor during plan startup for a CoerceToDomain
1680+
* expression node. The given constraints will be checked for each value
1681+
* passed through the node.
1682+
*/
1683+
List *
1684+
GetDomainConstraints(Oid typeOid)
1685+
{
1686+
List *result = NIL;
1687+
bool notNull = false;
1688+
Relation conRel;
1689+
1690+
conRel = heap_openr(ConstraintRelationName, AccessShareLock);
1691+
1692+
for (;;)
1693+
{
1694+
HeapTuple tup;
1695+
HeapTuple conTup;
1696+
Form_pg_type typTup;
1697+
ScanKeyData key[1];
1698+
SysScanDesc scan;
1699+
1700+
tup = SearchSysCache(TYPEOID,
1701+
ObjectIdGetDatum(typeOid),
1702+
0, 0, 0);
1703+
if (!HeapTupleIsValid(tup))
1704+
elog(ERROR, "GetDomainConstraints: failed to lookup type %u",
1705+
typeOid);
1706+
typTup = (Form_pg_type) GETSTRUCT(tup);
1707+
1708+
/* Test for NOT NULL Constraint */
1709+
if (typTup->typnotnull)
1710+
notNull = true;
1711+
1712+
/* Look for CHECK Constraints on this domain */
1713+
ScanKeyEntryInitialize(&key[0], 0x0,
1714+
Anum_pg_constraint_contypid, F_OIDEQ,
1715+
ObjectIdGetDatum(typeOid));
1716+
1717+
scan = systable_beginscan(conRel, ConstraintTypidIndex, true,
1718+
SnapshotNow, 1, key);
1719+
1720+
while (HeapTupleIsValid(conTup = systable_getnext(scan)))
1721+
{
1722+
Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
1723+
Datum val;
1724+
bool isNull;
1725+
Expr *check_expr;
1726+
DomainConstraintState *r;
1727+
1728+
/* Ignore non-CHECK constraints (presently, shouldn't be any) */
1729+
if (c->contype != CONSTRAINT_CHECK)
1730+
continue;
1731+
1732+
/* Not expecting conbin to be NULL, but we'll test for it anyway */
1733+
val = fastgetattr(conTup, Anum_pg_constraint_conbin,
1734+
conRel->rd_att, &isNull);
1735+
if (isNull)
1736+
elog(ERROR, "GetDomainConstraints: domain %s constraint %s has NULL conbin",
1737+
NameStr(typTup->typname), NameStr(c->conname));
1738+
1739+
check_expr = (Expr *)
1740+
stringToNode(DatumGetCString(DirectFunctionCall1(textout,
1741+
val)));
1742+
1743+
/* ExecInitExpr assumes we already fixed opfuncids */
1744+
fix_opfuncids((Node *) check_expr);
1745+
1746+
r = makeNode(DomainConstraintState);
1747+
r->constrainttype = DOM_CONSTRAINT_CHECK;
1748+
r->name = pstrdup(NameStr(c->conname));
1749+
r->check_expr = ExecInitExpr(check_expr, NULL);
1750+
1751+
/*
1752+
* use lcons() here because constraints of lower domains should
1753+
* be applied earlier.
1754+
*/
1755+
result = lcons(r, result);
1756+
}
1757+
1758+
systable_endscan(scan);
1759+
1760+
if (typTup->typtype != 'd')
1761+
{
1762+
/* Not a domain, so done */
1763+
ReleaseSysCache(tup);
1764+
break;
1765+
}
1766+
1767+
/* else loop to next domain in stack */
1768+
typeOid = typTup->typbasetype;
1769+
ReleaseSysCache(tup);
1770+
}
1771+
1772+
heap_close(conRel, AccessShareLock);
1773+
1774+
/*
1775+
* Only need to add one NOT NULL check regardless of how many domains
1776+
* in the stack request it.
1777+
*/
1778+
if (notNull)
1779+
{
1780+
DomainConstraintState *r = makeNode(DomainConstraintState);
1781+
1782+
r->constrainttype = DOM_CONSTRAINT_NOTNULL;
1783+
r->name = pstrdup("NOT NULL");
1784+
r->check_expr = NULL;
1785+
1786+
/* lcons to apply the nullness check FIRST */
1787+
result = lcons(r, result);
1788+
}
1789+
1790+
return result;
1791+
}
1792+
16721793
/*
16731794
* ALTER DOMAIN .. OWNER TO
16741795
*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy