Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+11-13
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

+125-4
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)