diff options
Diffstat (limited to 'src/backend/commands/typecmds.c')
-rw-r--r-- | src/backend/commands/typecmds.c | 114 |
1 files changed, 51 insertions, 63 deletions
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index e16942acd72..989bc36ee82 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.22 2002/12/12 15:49:24 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.23 2002/12/12 20:35:12 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -562,14 +562,14 @@ DefineDomain(CreateDomainStmt *stmt) break; case CONSTR_NOTNULL: - if (nullDefined) + if (nullDefined && !typNotNull) elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint"); typNotNull = true; nullDefined = true; break; case CONSTR_NULL: - if (nullDefined) + if (nullDefined && typNotNull) elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint"); typNotNull = false; nullDefined = true; @@ -644,14 +644,9 @@ DefineDomain(CreateDomainStmt *stmt) switch (constr->contype) { case CONSTR_CHECK: - { - char *junk; - - /* Returns the cooked constraint which is not needed during creation */ - junk = domainAddConstraint(domainoid, domainNamespace, - basetypeoid, stmt->typename->typmod, - constr, &counter, domainName); - } + domainAddConstraint(domainoid, domainNamespace, + basetypeoid, stmt->typename->typmod, + constr, &counter, domainName); break; /* Other constraint types were fully processed above */ @@ -1247,6 +1242,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) List *rels; List *rt; Form_pg_type typTup; + ExprContext *econtext; char *ccbin; Node *expr; int counter = 0; @@ -1261,7 +1257,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) /* Lock the type table */ rel = heap_openr(TypeRelationName, RowExclusiveLock); - /* Use LookupTypeName here so that shell types can be removed. */ + /* Use LookupTypeName here so that shell types can be found. */ domainoid = LookupTypeName(typename); if (!OidIsValid(domainoid)) elog(ERROR, "Type \"%s\" does not exist", @@ -1328,10 +1324,10 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) /* * Since all other constraint types throw errors, this must be - * a check constraint. + * a check constraint. First, process the constraint expression + * and add an entry to pg_constraint. */ - /* Returns the cooked constraint which is not needed during creation */ ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace, typTup->typbasetype, typTup->typtypmod, constr, &counter, NameStr(typTup->typname)); @@ -1342,61 +1338,46 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) */ expr = stringToNode(ccbin); fix_opfuncids(expr); + + /* Make an expression context for ExecQual */ + econtext = MakeExprContext(NULL, CurrentMemoryContext); + rels = get_rels_with_domain(domainoid); foreach (rt, rels) { - Relation typrel; + relToCheck *rtc = (relToCheck *) lfirst(rt); + Relation testrel; + TupleDesc tupdesc; HeapTuple tuple; HeapScanDesc scan; - TupleDesc tupdesc; - ExprContext *econtext; - TupleTableSlot *slot; - relToCheck *rtc = (relToCheck *) lfirst(rt); - - /* Lock relation */ - typrel = heap_open(rtc->relOid, ExclusiveLock); - /* Test attributes */ - tupdesc = RelationGetDescr(typrel); + /* Lock relation against changes */ + testrel = heap_open(rtc->relOid, ShareLock); - /* Make tuple slot to hold tuples */ - slot = MakeTupleTableSlot(); - ExecSetSlotDescriptor(slot, RelationGetDescr(typrel), false); - - /* Make an expression context for ExecQual */ - econtext = MakeExprContext(slot, CurrentMemoryContext); + tupdesc = RelationGetDescr(testrel); /* Scan through table */ - scan = heap_beginscan(typrel, SnapshotNow, 0, NULL); + scan = heap_beginscan(testrel, SnapshotNow, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { int i; - ExecStoreTuple(tuple, slot, InvalidBuffer, false); - /* Loop through each attribute of the tuple with a domain */ for (i = 0; i < rtc->natts; i++) { Datum d; bool isNull; Datum conResult; - ExprDoneCond isDone; d = heap_getattr(tuple, rtc->atts[i], tupdesc, &isNull); - if (isNull) - elog(ERROR, "ALTER DOMAIN: Relation \"%s\" Attribute \"%s\" " - "contains NULL values", - RelationGetRelationName(typrel), - NameStr(*attnumAttName(typrel, rtc->atts[i]))); - econtext->domainValue_datum = d; econtext->domainValue_isNull = isNull; - conResult = ExecEvalExpr(expr, econtext, &isNull, &isDone); + conResult = ExecEvalExpr(expr, econtext, &isNull, NULL); - if (!DatumGetBool(conResult)) + if (!isNull && !DatumGetBool(conResult)) elog(ERROR, "AlterDomainAddConstraint: Domain %s constraint %s failed", NameStr(typTup->typname), constr->name); } @@ -1406,13 +1387,12 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) heap_endscan(scan); - FreeExprContext(econtext); - pfree(slot); - - /* Hold type lock */ - heap_close(typrel, NoLock); + /* Hold relation lock till commit (XXX bad for concurrency) */ + heap_close(testrel, NoLock); } + FreeExprContext(econtext); + /* Clean up */ heap_close(rel, NoLock); } @@ -1524,11 +1504,12 @@ domainPermissionCheck(HeapTuple tup, TypeName *typename) /* - * domainAddConstraint + * domainAddConstraint - code shared between CREATE and ALTER DOMAIN */ -char * +static char * domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, - int typMod, Constraint *constr, int *counter, char *domainName) + int typMod, Constraint *constr, + int *counter, char *domainName) { Node *expr; char *ccsrc; @@ -1556,26 +1537,24 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, counter); /* - * Convert the A_EXPR in raw_expr into an - * EXPR + * Convert the A_EXPR in raw_expr into an EXPR */ pstate = make_parsestate(NULL); /* - * We want to have the domain VALUE node type filled in so - * that proper casting can occur. + * Set up a ConstraintTestValue 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->typeId = baseTypeOid; domVal->typeMod = typMod; - expr = transformExpr(pstate, constr->raw_expr, domVal); + pstate->p_value_substitute = (Node *) domVal; - /* - * Domains don't allow var clauses - */ - if (contain_var_clause(expr)) - elog(ERROR, "cannot use column references in domain CHECK clause"); + expr = transformExpr(pstate, constr->raw_expr); /* * Make sure it yields a boolean result. @@ -1590,6 +1569,13 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, elog(ERROR, "Relations cannot be referenced in domain CHECK constraint"); /* + * Domains don't allow var clauses (this should be redundant with the + * above check, but make it anyway) + */ + if (contain_var_clause(expr)) + elog(ERROR, "cannot use column references in domain CHECK clause"); + + /* * No subplans or aggregates, either... */ if (contain_subplans(expr)) @@ -1618,7 +1604,9 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, InvalidOid), false, false); - /* Write the constraint */ + /* + * Store the constraint in pg_constraint + */ CreateConstraintEntry(constr->name, /* Constraint Name */ domainNamespace, /* namespace */ CONSTRAINT_CHECK, /* Constraint Type */ @@ -1640,8 +1628,8 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, ccsrc); /* Source form check constraint */ /* - * Return the constraint so the calling routine can perform any additional - * required tests. + * Return the compiled constraint expression so the calling routine can + * perform any additional required tests. */ return ccbin; } |