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+ 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 *