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
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,
15551557char *ccsrc;
15561558char *ccbin;
15571559ParseState *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,
15821584pstate = make_parsestate(NULL);
15831585
15841586/*
1585- * Set up aConstraintTestValue to represent the occurrence of VALUE
1587+ * Set up aCoerceToDomainValue 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 );
15921594domVal->typeId = baseTypeOid;
15931595domVal->typeMod = typMod;
15941596
@@ -1669,6 +1671,125 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
16691671return 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+ boolnotNull = false;
1688+ RelationconRel;
1689+
1690+ conRel = heap_openr(ConstraintRelationName, AccessShareLock);
1691+
1692+ for (;;)
1693+ {
1694+ HeapTupletup;
1695+ HeapTupleconTup;
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_constraintc = (Form_pg_constraint) GETSTRUCT(conTup);
1723+ Datumval;
1724+ boolisNull;
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 *