8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
* DESCRIPTION
14
14
* The "DefineFoo" routines take the parse tree and pick out the
46
46
#include "commands/typecmds.h"
47
47
#include "executor/executor.h"
48
48
#include "miscadmin.h"
49
+ #include "nodes/execnodes.h"
49
50
#include "nodes/nodes.h"
50
51
#include "optimizer/clauses.h"
52
+ #include "optimizer/planmain.h"
51
53
#include "optimizer/var.h"
52
54
#include "parser/parse_coerce.h"
53
55
#include "parser/parse_expr.h"
@@ -1555,7 +1557,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
1555
1557
char * ccsrc ;
1556
1558
char * ccbin ;
1557
1559
ParseState * pstate ;
1558
- ConstraintTestValue * domVal ;
1560
+ CoerceToDomainValue * domVal ;
1559
1561
1560
1562
/*
1561
1563
* Assign or validate constraint name
@@ -1582,13 +1584,13 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
1582
1584
pstate = make_parsestate (NULL );
1583
1585
1584
1586
/*
1585
- * Set up a ConstraintTestValue to represent the occurrence of VALUE
1587
+ * Set up a CoerceToDomainValue to represent the occurrence of VALUE
1586
1588
* in the expression. Note that it will appear to have the type of the
1587
1589
* base type, not the domain. This seems correct since within the
1588
1590
* check expression, we should not assume the input value can be considered
1589
1591
* a member of the domain.
1590
1592
*/
1591
- domVal = makeNode (ConstraintTestValue );
1593
+ domVal = makeNode (CoerceToDomainValue );
1592
1594
domVal -> typeId = baseTypeOid ;
1593
1595
domVal -> typeMod = typMod ;
1594
1596
@@ -1669,6 +1671,125 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
1669
1671
return ccbin ;
1670
1672
}
1671
1673
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
+
1672
1793
/*
1673
1794
* ALTER DOMAIN .. OWNER TO
1674
1795
*
0 commit comments