-/*
- * 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.
- *
- * We allow this to be called for non-domain types, in which case the result
- * is always NIL.
- */
-List *
-GetDomainConstraints(Oid typeOid)
-{
- List *result = NIL;
- bool notNull = false;
- Relation conRel;
-
- conRel = heap_open(ConstraintRelationId, AccessShareLock);
-
- for (;;)
- {
- HeapTuple tup;
- HeapTuple conTup;
- Form_pg_type typTup;
- ScanKeyData key[1];
- SysScanDesc scan;
-
- tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "cache lookup failed for type %u", typeOid);
- typTup = (Form_pg_type) GETSTRUCT(tup);
-
- if (typTup->typtype != TYPTYPE_DOMAIN)
- {
- /* Not a domain, so done */
- ReleaseSysCache(tup);
- break;
- }
-
- /* Test for NOT NULL Constraint */
- if (typTup->typnotnull)
- notNull = true;
-
- /* Look for CHECK Constraints on this domain */
- ScanKeyInit(&key[0],
- Anum_pg_constraint_contypid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(typeOid));
-
- scan = systable_beginscan(conRel, ConstraintTypidIndexId, 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, "domain \"%s\" constraint \"%s\" has NULL conbin",
- NameStr(typTup->typname), NameStr(c->conname));
-
- check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
-
- /* ExecInitExpr assumes we've planned the expression */
- check_expr = expression_planner(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);
-
- /* 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;
-}
-