diff options
Diffstat (limited to 'src/backend/commands/typecmds.c')
-rw-r--r-- | src/backend/commands/typecmds.c | 129 |
1 files changed, 125 insertions, 4 deletions
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 379e4bb9b45..ad954605373 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.29 2003/01/08 22:06:23 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.30 2003/02/03 21:15:43 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -46,8 +46,10 @@ #include "commands/typecmds.h" #include "executor/executor.h" #include "miscadmin.h" +#include "nodes/execnodes.h" #include "nodes/nodes.h" #include "optimizer/clauses.h" +#include "optimizer/planmain.h" #include "optimizer/var.h" #include "parser/parse_coerce.h" #include "parser/parse_expr.h" @@ -1555,7 +1557,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, char *ccsrc; char *ccbin; ParseState *pstate; - ConstraintTestValue *domVal; + CoerceToDomainValue *domVal; /* * Assign or validate constraint name @@ -1582,13 +1584,13 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, pstate = make_parsestate(NULL); /* - * Set up a ConstraintTestValue to represent the occurrence of VALUE + * Set up a CoerceToDomainValue to represent the occurrence of VALUE * in the expression. Note that it will appear to have the type of the * base type, not the domain. This seems correct since within the * check expression, we should not assume the input value can be considered * a member of the domain. */ - domVal = makeNode(ConstraintTestValue); + domVal = makeNode(CoerceToDomainValue); domVal->typeId = baseTypeOid; domVal->typeMod = typMod; @@ -1670,6 +1672,125 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, } /* + * GetDomainConstraints - get a list of the current constraints of domain + * + * Returns a possibly-empty list of DomainConstraintState nodes. + * + * This is called by the executor during plan startup for a CoerceToDomain + * expression node. The given constraints will be checked for each value + * passed through the node. + */ +List * +GetDomainConstraints(Oid typeOid) +{ + List *result = NIL; + bool notNull = false; + Relation conRel; + + conRel = heap_openr(ConstraintRelationName, AccessShareLock); + + for (;;) + { + HeapTuple tup; + HeapTuple conTup; + Form_pg_type typTup; + ScanKeyData key[1]; + SysScanDesc scan; + + tup = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typeOid), + 0, 0, 0); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "GetDomainConstraints: failed to lookup type %u", + typeOid); + typTup = (Form_pg_type) GETSTRUCT(tup); + + /* Test for NOT NULL Constraint */ + if (typTup->typnotnull) + notNull = true; + + /* Look for CHECK Constraints on this domain */ + ScanKeyEntryInitialize(&key[0], 0x0, + Anum_pg_constraint_contypid, F_OIDEQ, + ObjectIdGetDatum(typeOid)); + + scan = systable_beginscan(conRel, ConstraintTypidIndex, true, + SnapshotNow, 1, key); + + while (HeapTupleIsValid(conTup = systable_getnext(scan))) + { + Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup); + Datum val; + bool isNull; + Expr *check_expr; + DomainConstraintState *r; + + /* Ignore non-CHECK constraints (presently, shouldn't be any) */ + if (c->contype != CONSTRAINT_CHECK) + continue; + + /* Not expecting conbin to be NULL, but we'll test for it anyway */ + val = fastgetattr(conTup, Anum_pg_constraint_conbin, + conRel->rd_att, &isNull); + if (isNull) + elog(ERROR, "GetDomainConstraints: domain %s constraint %s has NULL conbin", + NameStr(typTup->typname), NameStr(c->conname)); + + check_expr = (Expr *) + stringToNode(DatumGetCString(DirectFunctionCall1(textout, + val))); + + /* ExecInitExpr assumes we already fixed opfuncids */ + fix_opfuncids((Node *) check_expr); + + r = makeNode(DomainConstraintState); + r->constrainttype = DOM_CONSTRAINT_CHECK; + r->name = pstrdup(NameStr(c->conname)); + r->check_expr = ExecInitExpr(check_expr, NULL); + + /* + * use lcons() here because constraints of lower domains should + * be applied earlier. + */ + result = lcons(r, result); + } + + systable_endscan(scan); + + if (typTup->typtype != 'd') + { + /* Not a domain, so done */ + ReleaseSysCache(tup); + break; + } + + /* else loop to next domain in stack */ + typeOid = typTup->typbasetype; + ReleaseSysCache(tup); + } + + heap_close(conRel, AccessShareLock); + + /* + * Only need to add one NOT NULL check regardless of how many domains + * in the stack request it. + */ + if (notNull) + { + DomainConstraintState *r = makeNode(DomainConstraintState); + + r->constrainttype = DOM_CONSTRAINT_NOTNULL; + r->name = pstrdup("NOT NULL"); + r->check_expr = NULL; + + /* lcons to apply the nullness check FIRST */ + result = lcons(r, result); + } + + return result; +} + +/* * ALTER DOMAIN .. OWNER TO * * Eventually this should allow changing ownership of other kinds of types, |