Determine the set of constraints applied to a domain at executor
startup, not in the parser; this allows ALTER DOMAIN to work correctly with domain constraint operations stored in rules. Rod Taylor; code review by Tom Lane.
This commit is contained in:
parent
464598b637
commit
3752e85bad
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.188 2003/01/10 22:03:27 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.189 2003/02/03 21:15:43 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -853,7 +853,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||
}
|
||||
}
|
||||
|
||||
/* If it's a domain type, get info on domain constraints */
|
||||
/* If it's a domain type, set up to check domain constraints */
|
||||
if (get_typtype(attr[i]->atttypid) == 'd')
|
||||
{
|
||||
Param *prm;
|
||||
@ -863,25 +863,23 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
||||
* Easiest way to do this is to use parse_coerce.c to set up
|
||||
* an expression that checks the constraints. (At present,
|
||||
* the expression might contain a length-coercion-function call
|
||||
* and/or ConstraintTest nodes.) The bottom of the expression
|
||||
* and/or CoerceToDomain nodes.) The bottom of the expression
|
||||
* is a Param node so that we can fill in the actual datum during
|
||||
* the data input loop.
|
||||
*/
|
||||
prm = makeNode(Param);
|
||||
prm->paramkind = PARAM_EXEC;
|
||||
prm->paramid = 0;
|
||||
prm->paramtype = attr[i]->atttypid;
|
||||
prm->paramtype = getBaseType(attr[i]->atttypid);
|
||||
|
||||
node = coerce_type_constraints((Node *) prm, attr[i]->atttypid,
|
||||
COERCE_IMPLICIT_CAST);
|
||||
node = coerce_to_domain((Node *) prm,
|
||||
prm->paramtype,
|
||||
attr[i]->atttypid,
|
||||
COERCE_IMPLICIT_CAST);
|
||||
|
||||
/* check whether any constraints actually found */
|
||||
if (node != (Node *) prm)
|
||||
{
|
||||
constraintexprs[i] = ExecPrepareExpr((Expr *) node,
|
||||
estate);
|
||||
hasConstraints = true;
|
||||
}
|
||||
constraintexprs[i] = ExecPrepareExpr((Expr *) node,
|
||||
estate);
|
||||
hasConstraints = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ -1669,6 +1671,125 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
|
||||
return ccbin;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.123 2003/01/12 04:03:34 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.124 2003/02/03 21:15:43 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -36,6 +36,7 @@
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/typecmds.h"
|
||||
#include "executor/execdebug.h"
|
||||
#include "executor/functions.h"
|
||||
#include "executor/nodeSubplan.h"
|
||||
@ -80,10 +81,10 @@ static Datum ExecEvalNullTest(GenericExprState *nstate,
|
||||
static Datum ExecEvalBooleanTest(GenericExprState *bstate,
|
||||
ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalConstraintTest(ConstraintTestState *cstate,
|
||||
static Datum ExecEvalCoerceToDomain(CoerceToDomainState *cstate,
|
||||
ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalConstraintTestValue(ConstraintTestValue *conVal,
|
||||
static Datum ExecEvalCoerceToDomainValue(CoerceToDomainValue *conVal,
|
||||
ExprContext *econtext, bool *isNull);
|
||||
static Datum ExecEvalFieldSelect(GenericExprState *fstate,
|
||||
ExprContext *econtext,
|
||||
@ -1559,32 +1560,37 @@ ExecEvalBooleanTest(GenericExprState *bstate,
|
||||
}
|
||||
|
||||
/*
|
||||
* ExecEvalConstraintTest
|
||||
* ExecEvalCoerceToDomain
|
||||
*
|
||||
* Test the constraint against the data provided. If the data fits
|
||||
* within the constraint specifications, pass it through (return the
|
||||
* Test the provided data against the domain constraint(s). If the data
|
||||
* passes the constraint specifications, pass it through (return the
|
||||
* datum) otherwise throw an error.
|
||||
*/
|
||||
static Datum
|
||||
ExecEvalConstraintTest(ConstraintTestState *cstate, ExprContext *econtext,
|
||||
ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone)
|
||||
{
|
||||
ConstraintTest *constraint = (ConstraintTest *) cstate->xprstate.expr;
|
||||
CoerceToDomain *ctest = (CoerceToDomain *) cstate->xprstate.expr;
|
||||
Datum result;
|
||||
List *l;
|
||||
|
||||
result = ExecEvalExpr(cstate->arg, econtext, isNull, isDone);
|
||||
|
||||
if (isDone && *isDone == ExprEndResult)
|
||||
return result; /* nothing to check */
|
||||
|
||||
switch (constraint->testtype)
|
||||
foreach(l, cstate->constraints)
|
||||
{
|
||||
case CONSTR_TEST_NOTNULL:
|
||||
if (*isNull)
|
||||
elog(ERROR, "Domain %s does not allow NULL values",
|
||||
constraint->domname);
|
||||
break;
|
||||
case CONSTR_TEST_CHECK:
|
||||
DomainConstraintState *con = (DomainConstraintState *) lfirst(l);
|
||||
|
||||
switch (con->constrainttype)
|
||||
{
|
||||
case DOM_CONSTRAINT_NOTNULL:
|
||||
if (*isNull)
|
||||
elog(ERROR, "Domain %s does not allow NULL values",
|
||||
format_type_be(ctest->resulttype));
|
||||
break;
|
||||
case DOM_CONSTRAINT_CHECK:
|
||||
{
|
||||
Datum conResult;
|
||||
bool conIsNull;
|
||||
@ -1592,7 +1598,7 @@ ExecEvalConstraintTest(ConstraintTestState *cstate, ExprContext *econtext,
|
||||
bool save_isNull;
|
||||
|
||||
/*
|
||||
* Set up value to be returned by ConstraintTestValue nodes.
|
||||
* Set up value to be returned by CoerceToDomainValue nodes.
|
||||
* We must save and restore prior setting of econtext's
|
||||
* domainValue fields, in case this node is itself within
|
||||
* a check expression for another domain.
|
||||
@ -1603,35 +1609,37 @@ ExecEvalConstraintTest(ConstraintTestState *cstate, ExprContext *econtext,
|
||||
econtext->domainValue_datum = result;
|
||||
econtext->domainValue_isNull = *isNull;
|
||||
|
||||
conResult = ExecEvalExpr(cstate->check_expr,
|
||||
conResult = ExecEvalExpr(con->check_expr,
|
||||
econtext, &conIsNull, NULL);
|
||||
|
||||
if (!conIsNull &&
|
||||
!DatumGetBool(conResult))
|
||||
elog(ERROR, "ExecEvalConstraintTest: Domain %s constraint %s failed",
|
||||
constraint->domname, constraint->name);
|
||||
elog(ERROR, "ExecEvalCoerceToDomain: Domain %s constraint %s failed",
|
||||
format_type_be(ctest->resulttype), con->name);
|
||||
|
||||
econtext->domainValue_datum = save_datum;
|
||||
econtext->domainValue_isNull = save_isNull;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "ExecEvalConstraintTest: Constraint type unknown");
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "ExecEvalCoerceToDomain: Constraint type unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If all has gone well (constraint did not fail) return the datum */
|
||||
/* If all has gone well (constraints did not fail) return the datum */
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* ExecEvalConstraintTestValue
|
||||
* ExecEvalCoerceToDomainValue
|
||||
*
|
||||
* Return the value stored by constraintTest.
|
||||
* Return the value stored by CoerceToDomain.
|
||||
*/
|
||||
static Datum
|
||||
ExecEvalConstraintTestValue(ConstraintTestValue *conVal, ExprContext *econtext,
|
||||
bool *isNull)
|
||||
ExecEvalCoerceToDomainValue(CoerceToDomainValue *conVal,
|
||||
ExprContext *econtext, bool *isNull)
|
||||
{
|
||||
*isNull = econtext->domainValue_isNull;
|
||||
return econtext->domainValue_datum;
|
||||
@ -1830,14 +1838,14 @@ ExecEvalExpr(ExprState *expression,
|
||||
isNull,
|
||||
isDone);
|
||||
break;
|
||||
case T_ConstraintTest:
|
||||
retDatum = ExecEvalConstraintTest((ConstraintTestState *) expression,
|
||||
case T_CoerceToDomain:
|
||||
retDatum = ExecEvalCoerceToDomain((CoerceToDomainState *) expression,
|
||||
econtext,
|
||||
isNull,
|
||||
isDone);
|
||||
break;
|
||||
case T_ConstraintTestValue:
|
||||
retDatum = ExecEvalConstraintTestValue((ConstraintTestValue *) expr,
|
||||
case T_CoerceToDomainValue:
|
||||
retDatum = ExecEvalCoerceToDomainValue((CoerceToDomainValue *) expr,
|
||||
econtext,
|
||||
isNull);
|
||||
break;
|
||||
@ -1915,7 +1923,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
|
||||
case T_Var:
|
||||
case T_Const:
|
||||
case T_Param:
|
||||
case T_ConstraintTestValue:
|
||||
case T_CoerceToDomainValue:
|
||||
/* No special setup needed for these node types */
|
||||
state = (ExprState *) makeNode(ExprState);
|
||||
break;
|
||||
@ -2092,13 +2100,13 @@ ExecInitExpr(Expr *node, PlanState *parent)
|
||||
state = (ExprState *) gstate;
|
||||
}
|
||||
break;
|
||||
case T_ConstraintTest:
|
||||
case T_CoerceToDomain:
|
||||
{
|
||||
ConstraintTest *ctest = (ConstraintTest *) node;
|
||||
ConstraintTestState *cstate = makeNode(ConstraintTestState);
|
||||
CoerceToDomain *ctest = (CoerceToDomain *) node;
|
||||
CoerceToDomainState *cstate = makeNode(CoerceToDomainState);
|
||||
|
||||
cstate->arg = ExecInitExpr(ctest->arg, parent);
|
||||
cstate->check_expr = ExecInitExpr(ctest->check_expr, parent);
|
||||
cstate->constraints = GetDomainConstraints(ctest->resulttype);
|
||||
state = (ExprState *) cstate;
|
||||
}
|
||||
break;
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.238 2003/01/23 23:38:56 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.239 2003/02/03 21:15:43 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -933,29 +933,28 @@ _copyBooleanTest(BooleanTest *from)
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyConstraintTest
|
||||
* _copyCoerceToDomain
|
||||
*/
|
||||
static ConstraintTest *
|
||||
_copyConstraintTest(ConstraintTest *from)
|
||||
static CoerceToDomain *
|
||||
_copyCoerceToDomain(CoerceToDomain *from)
|
||||
{
|
||||
ConstraintTest *newnode = makeNode(ConstraintTest);
|
||||
CoerceToDomain *newnode = makeNode(CoerceToDomain);
|
||||
|
||||
COPY_NODE_FIELD(arg);
|
||||
COPY_SCALAR_FIELD(testtype);
|
||||
COPY_STRING_FIELD(name);
|
||||
COPY_STRING_FIELD(domname);
|
||||
COPY_NODE_FIELD(check_expr);
|
||||
COPY_SCALAR_FIELD(resulttype);
|
||||
COPY_SCALAR_FIELD(resulttypmod);
|
||||
COPY_SCALAR_FIELD(coercionformat);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyConstraintTestValue
|
||||
* _copyCoerceToDomainValue
|
||||
*/
|
||||
static ConstraintTestValue *
|
||||
_copyConstraintTestValue(ConstraintTestValue *from)
|
||||
static CoerceToDomainValue *
|
||||
_copyCoerceToDomainValue(CoerceToDomainValue *from)
|
||||
{
|
||||
ConstraintTestValue *newnode = makeNode(ConstraintTestValue);
|
||||
CoerceToDomainValue *newnode = makeNode(CoerceToDomainValue);
|
||||
|
||||
COPY_SCALAR_FIELD(typeId);
|
||||
COPY_SCALAR_FIELD(typeMod);
|
||||
@ -2476,11 +2475,11 @@ copyObject(void *from)
|
||||
case T_BooleanTest:
|
||||
retval = _copyBooleanTest(from);
|
||||
break;
|
||||
case T_ConstraintTest:
|
||||
retval = _copyConstraintTest(from);
|
||||
case T_CoerceToDomain:
|
||||
retval = _copyCoerceToDomain(from);
|
||||
break;
|
||||
case T_ConstraintTestValue:
|
||||
retval = _copyConstraintTestValue(from);
|
||||
case T_CoerceToDomainValue:
|
||||
retval = _copyCoerceToDomainValue(from);
|
||||
break;
|
||||
case T_TargetEntry:
|
||||
retval = _copyTargetEntry(from);
|
||||
|
@ -18,7 +18,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.182 2003/01/23 23:38:56 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.183 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -383,19 +383,25 @@ _equalBooleanTest(BooleanTest *a, BooleanTest *b)
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalConstraintTest(ConstraintTest *a, ConstraintTest *b)
|
||||
_equalCoerceToDomain(CoerceToDomain *a, CoerceToDomain *b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(arg);
|
||||
COMPARE_SCALAR_FIELD(testtype);
|
||||
COMPARE_STRING_FIELD(name);
|
||||
COMPARE_STRING_FIELD(domname);
|
||||
COMPARE_NODE_FIELD(check_expr);
|
||||
COMPARE_SCALAR_FIELD(resulttype);
|
||||
COMPARE_SCALAR_FIELD(resulttypmod);
|
||||
/*
|
||||
* Special-case COERCE_DONTCARE, so that pathkeys can build coercion
|
||||
* nodes that are equal() to both explicit and implicit coercions.
|
||||
*/
|
||||
if (a->coercionformat != b->coercionformat &&
|
||||
a->coercionformat != COERCE_DONTCARE &&
|
||||
b->coercionformat != COERCE_DONTCARE)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalConstraintTestValue(ConstraintTestValue *a, ConstraintTestValue *b)
|
||||
_equalCoerceToDomainValue(CoerceToDomainValue *a, CoerceToDomainValue *b)
|
||||
{
|
||||
COMPARE_SCALAR_FIELD(typeId);
|
||||
COMPARE_SCALAR_FIELD(typeMod);
|
||||
@ -1599,11 +1605,11 @@ equal(void *a, void *b)
|
||||
case T_BooleanTest:
|
||||
retval = _equalBooleanTest(a, b);
|
||||
break;
|
||||
case T_ConstraintTest:
|
||||
retval = _equalConstraintTest(a, b);
|
||||
case T_CoerceToDomain:
|
||||
retval = _equalCoerceToDomain(a, b);
|
||||
break;
|
||||
case T_ConstraintTestValue:
|
||||
retval = _equalConstraintTestValue(a, b);
|
||||
case T_CoerceToDomainValue:
|
||||
retval = _equalCoerceToDomainValue(a, b);
|
||||
break;
|
||||
case T_TargetEntry:
|
||||
retval = _equalTargetEntry(a, b);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.194 2003/01/20 18:54:47 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.195 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every node type that can appear in stored rules' parsetrees *must*
|
||||
@ -745,21 +745,20 @@ _outBooleanTest(StringInfo str, BooleanTest *node)
|
||||
}
|
||||
|
||||
static void
|
||||
_outConstraintTest(StringInfo str, ConstraintTest *node)
|
||||
_outCoerceToDomain(StringInfo str, CoerceToDomain *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("CONSTRAINTTEST");
|
||||
WRITE_NODE_TYPE("COERCETODOMAIN");
|
||||
|
||||
WRITE_NODE_FIELD(arg);
|
||||
WRITE_ENUM_FIELD(testtype, ConstraintTestType);
|
||||
WRITE_STRING_FIELD(name);
|
||||
WRITE_STRING_FIELD(domname);
|
||||
WRITE_NODE_FIELD(check_expr);
|
||||
WRITE_OID_FIELD(resulttype);
|
||||
WRITE_INT_FIELD(resulttypmod);
|
||||
WRITE_ENUM_FIELD(coercionformat, CoercionForm);
|
||||
}
|
||||
|
||||
static void
|
||||
_outConstraintTestValue(StringInfo str, ConstraintTestValue *node)
|
||||
_outCoerceToDomainValue(StringInfo str, CoerceToDomainValue *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("CONSTRAINTTESTVALUE");
|
||||
WRITE_NODE_TYPE("COERCETODOMAINVALUE");
|
||||
|
||||
WRITE_OID_FIELD(typeId);
|
||||
WRITE_INT_FIELD(typeMod);
|
||||
@ -1548,11 +1547,11 @@ _outNode(StringInfo str, void *obj)
|
||||
case T_BooleanTest:
|
||||
_outBooleanTest(str, obj);
|
||||
break;
|
||||
case T_ConstraintTest:
|
||||
_outConstraintTest(str, obj);
|
||||
case T_CoerceToDomain:
|
||||
_outCoerceToDomain(str, obj);
|
||||
break;
|
||||
case T_ConstraintTestValue:
|
||||
_outConstraintTestValue(str, obj);
|
||||
case T_CoerceToDomainValue:
|
||||
_outCoerceToDomainValue(str, obj);
|
||||
break;
|
||||
case T_TargetEntry:
|
||||
_outTargetEntry(str, obj);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.146 2003/01/10 21:08:11 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.147 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Path and Plan nodes do not have any readfuncs support, because we
|
||||
@ -635,29 +635,28 @@ _readBooleanTest(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* _readConstraintTest
|
||||
* _readCoerceToDomain
|
||||
*/
|
||||
static ConstraintTest *
|
||||
_readConstraintTest(void)
|
||||
static CoerceToDomain *
|
||||
_readCoerceToDomain(void)
|
||||
{
|
||||
READ_LOCALS(ConstraintTest);
|
||||
READ_LOCALS(CoerceToDomain);
|
||||
|
||||
READ_NODE_FIELD(arg);
|
||||
READ_ENUM_FIELD(testtype, ConstraintTestType);
|
||||
READ_STRING_FIELD(name);
|
||||
READ_STRING_FIELD(domname);
|
||||
READ_NODE_FIELD(check_expr);
|
||||
READ_OID_FIELD(resulttype);
|
||||
READ_INT_FIELD(resulttypmod);
|
||||
READ_ENUM_FIELD(coercionformat, CoercionForm);
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
/*
|
||||
* _readConstraintTestValue
|
||||
* _readCoerceToDomainValue
|
||||
*/
|
||||
static ConstraintTestValue *
|
||||
_readConstraintTestValue(void)
|
||||
static CoerceToDomainValue *
|
||||
_readCoerceToDomainValue(void)
|
||||
{
|
||||
READ_LOCALS(ConstraintTestValue);
|
||||
READ_LOCALS(CoerceToDomainValue);
|
||||
|
||||
READ_OID_FIELD(typeId);
|
||||
READ_INT_FIELD(typeMod);
|
||||
@ -900,10 +899,10 @@ parseNodeString(void)
|
||||
return_value = _readNullTest();
|
||||
else if (MATCH("BOOLEANTEST", 11))
|
||||
return_value = _readBooleanTest();
|
||||
else if (MATCH("CONSTRAINTTEST", 14))
|
||||
return_value = _readConstraintTest();
|
||||
else if (MATCH("CONSTRAINTTESTVALUE", 19))
|
||||
return_value = _readConstraintTestValue();
|
||||
else if (MATCH("COERCETODOMAIN", 14))
|
||||
return_value = _readCoerceToDomain();
|
||||
else if (MATCH("COERCETODOMAINVALUE", 19))
|
||||
return_value = _readCoerceToDomainValue();
|
||||
else if (MATCH("TARGETENTRY", 11))
|
||||
return_value = _readTargetEntry();
|
||||
else if (MATCH("RANGETBLREF", 11))
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.56 2003/01/28 22:13:29 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.57 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -540,6 +540,14 @@ clause_selectivity(Query *root,
|
||||
varRelid,
|
||||
jointype);
|
||||
}
|
||||
else if (IsA(clause, CoerceToDomain))
|
||||
{
|
||||
/* Not sure this case is needed, but it can't hurt */
|
||||
s1 = clause_selectivity(root,
|
||||
(Node *) ((CoerceToDomain *) clause)->arg,
|
||||
varRelid,
|
||||
jointype);
|
||||
}
|
||||
|
||||
#ifdef SELECTIVITY_DEBUG
|
||||
elog(DEBUG3, "clause_selectivity: s1 %f", s1);
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.59 2002/12/12 15:49:32 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.60 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -185,9 +185,10 @@ expand_targetlist(List *tlist, int command_type,
|
||||
true, /* isnull */
|
||||
att_tup->attbyval);
|
||||
if (!att_tup->attisdropped)
|
||||
new_expr = coerce_type_constraints(new_expr,
|
||||
atttype,
|
||||
COERCE_IMPLICIT_CAST);
|
||||
new_expr = coerce_to_domain(new_expr,
|
||||
InvalidOid,
|
||||
atttype,
|
||||
COERCE_IMPLICIT_CAST);
|
||||
break;
|
||||
case CMD_UPDATE:
|
||||
/* Insert NULLs for dropped columns */
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.125 2003/01/20 18:54:54 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.126 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -2030,7 +2030,7 @@ expression_tree_walker(Node *node,
|
||||
case T_Var:
|
||||
case T_Const:
|
||||
case T_Param:
|
||||
case T_ConstraintTestValue:
|
||||
case T_CoerceToDomainValue:
|
||||
case T_RangeTblRef:
|
||||
/* primitive node types with no subnodes */
|
||||
break;
|
||||
@ -2148,10 +2148,8 @@ expression_tree_walker(Node *node,
|
||||
return walker(((NullTest *) node)->arg, context);
|
||||
case T_BooleanTest:
|
||||
return walker(((BooleanTest *) node)->arg, context);
|
||||
case T_ConstraintTest:
|
||||
if (walker(((ConstraintTest *) node)->arg, context))
|
||||
return true;
|
||||
return walker(((ConstraintTest *) node)->check_expr, context);
|
||||
case T_CoerceToDomain:
|
||||
return walker(((CoerceToDomain *) node)->arg, context);
|
||||
case T_TargetEntry:
|
||||
return walker(((TargetEntry *) node)->expr, context);
|
||||
case T_Query:
|
||||
@ -2374,7 +2372,7 @@ expression_tree_mutator(Node *node,
|
||||
case T_Var:
|
||||
case T_Const:
|
||||
case T_Param:
|
||||
case T_ConstraintTestValue:
|
||||
case T_CoerceToDomainValue:
|
||||
case T_RangeTblRef:
|
||||
/* primitive node types with no subnodes */
|
||||
return (Node *) copyObject(node);
|
||||
@ -2538,14 +2536,13 @@ expression_tree_mutator(Node *node,
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_ConstraintTest:
|
||||
case T_CoerceToDomain:
|
||||
{
|
||||
ConstraintTest *ctest = (ConstraintTest *) node;
|
||||
ConstraintTest *newnode;
|
||||
CoerceToDomain *ctest = (CoerceToDomain *) node;
|
||||
CoerceToDomain *newnode;
|
||||
|
||||
FLATCOPY(newnode, ctest, ConstraintTest);
|
||||
FLATCOPY(newnode, ctest, CoerceToDomain);
|
||||
MUTATE(newnode->arg, ctest->arg, Expr *);
|
||||
MUTATE(newnode->check_expr, ctest->check_expr, Expr *);
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
|
@ -8,18 +8,13 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.91 2002/12/12 20:35:13 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.92 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/pg_cast.h"
|
||||
#include "catalog/pg_constraint.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "optimizer/clauses.h"
|
||||
@ -35,7 +30,7 @@
|
||||
|
||||
static Node *coerce_type_typmod(Node *node,
|
||||
Oid targetTypeId, int32 targetTypMod,
|
||||
CoercionForm cformat);
|
||||
CoercionForm cformat, bool isExplicit);
|
||||
static Oid PreferredType(CATEGORY category, Oid type);
|
||||
static Node *build_func_call(Oid funcid, Oid rettype, List *args,
|
||||
CoercionForm fformat);
|
||||
@ -103,7 +98,9 @@ coerce_to_target_type(Node *expr, Oid exprtype,
|
||||
* as well as a type coercion.
|
||||
*/
|
||||
if (expr != NULL)
|
||||
expr = coerce_type_typmod(expr, targettype, targettypmod, cformat);
|
||||
expr = coerce_type_typmod(expr, targettype, targettypmod,
|
||||
cformat,
|
||||
(cformat != COERCE_IMPLICIT_CAST));
|
||||
|
||||
return expr;
|
||||
}
|
||||
@ -119,7 +116,7 @@ coerce_to_target_type(Node *expr, Oid exprtype,
|
||||
* No coercion to a typmod (length) is performed here. The caller must
|
||||
* call coerce_type_typmod as well, if a typmod constraint is wanted.
|
||||
* (But if the target type is a domain, it may internally contain a
|
||||
* typmod constraint, which will be applied inside coerce_type_constraints.)
|
||||
* typmod constraint, which will be applied inside coerce_to_domain.)
|
||||
*/
|
||||
Node *
|
||||
coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
|
||||
@ -186,15 +183,8 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
|
||||
|
||||
/* If target is a domain, apply constraints. */
|
||||
if (targetTyptype == 'd')
|
||||
{
|
||||
result = coerce_type_constraints(result, targetTypeId,
|
||||
cformat);
|
||||
/* We might now need a RelabelType. */
|
||||
if (exprType(result) != targetTypeId)
|
||||
result = (Node *) makeRelabelType((Expr *) result,
|
||||
targetTypeId, -1,
|
||||
cformat);
|
||||
}
|
||||
result = coerce_to_domain(result, InvalidOid, targetTypeId,
|
||||
cformat);
|
||||
|
||||
ReleaseSysCache(targetType);
|
||||
}
|
||||
@ -222,17 +212,12 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
|
||||
cformat);
|
||||
|
||||
/*
|
||||
* If domain, test against domain constraints and relabel with
|
||||
* If domain, coerce to the domain type and relabel with
|
||||
* domain type ID
|
||||
*/
|
||||
if (targetTypeId != baseTypeId)
|
||||
{
|
||||
result = coerce_type_constraints(result, targetTypeId,
|
||||
cformat);
|
||||
result = (Node *) makeRelabelType((Expr *) result,
|
||||
targetTypeId, -1,
|
||||
cformat);
|
||||
}
|
||||
result = coerce_to_domain(result, baseTypeId, targetTypeId,
|
||||
cformat);
|
||||
|
||||
/*
|
||||
* If the input is a constant, apply the type conversion
|
||||
@ -257,21 +242,23 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
|
||||
* higher-level code.
|
||||
*
|
||||
* Also, domains may have value restrictions beyond the base type
|
||||
* that must be accounted for.
|
||||
* that must be accounted for. If the destination is a domain
|
||||
* then we won't need a RelabelType node.
|
||||
*/
|
||||
result = coerce_type_constraints(node, targetTypeId,
|
||||
cformat);
|
||||
|
||||
/*
|
||||
* XXX could we label result with exprTypmod(node) instead of
|
||||
* default -1 typmod, to save a possible length-coercion
|
||||
* later? Would work if both types have same interpretation of
|
||||
* typmod, which is likely but not certain (wrong if target is
|
||||
* a domain, in any case).
|
||||
*/
|
||||
result = (Node *) makeRelabelType((Expr *) result,
|
||||
targetTypeId, -1,
|
||||
cformat);
|
||||
result = coerce_to_domain(node, InvalidOid, targetTypeId,
|
||||
cformat);
|
||||
if (result == node)
|
||||
{
|
||||
/*
|
||||
* XXX could we label result with exprTypmod(node) instead of
|
||||
* default -1 typmod, to save a possible length-coercion
|
||||
* later? Would work if both types have same interpretation of
|
||||
* typmod, which is likely but not certain.
|
||||
*/
|
||||
result = (Node *) makeRelabelType((Expr *) result,
|
||||
targetTypeId, -1,
|
||||
cformat);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (typeInheritsFrom(inputTypeId, targetTypeId))
|
||||
@ -392,120 +379,61 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
|
||||
|
||||
|
||||
/*
|
||||
* Create an expression tree to enforce the constraints (if any)
|
||||
* that should be applied by the type. Currently this is only
|
||||
* interesting for domain types.
|
||||
* Create an expression tree to represent coercion to a domain type.
|
||||
*
|
||||
* NOTE: result tree is not guaranteed to show the correct exprType() for
|
||||
* the domain; it may show the base type. Caller must relabel if needed.
|
||||
* 'arg': input expression
|
||||
* 'baseTypeId': base type of domain, if known (pass InvalidOid if caller
|
||||
* has not bothered to look this up)
|
||||
* 'typeId': target type to coerce to
|
||||
* 'cformat': coercion format
|
||||
*
|
||||
* If the target type isn't a domain, the given 'arg' is returned as-is.
|
||||
*/
|
||||
Node *
|
||||
coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
|
||||
coerce_to_domain(Node *arg, Oid baseTypeId, Oid typeId, CoercionForm cformat)
|
||||
{
|
||||
char *notNull = NULL;
|
||||
int32 typmod = -1;
|
||||
CoerceToDomain *result;
|
||||
int32 typmod;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
HeapTuple tup;
|
||||
HeapTuple conTup;
|
||||
Form_pg_type typTup;
|
||||
/* Get the base type if it hasn't been supplied */
|
||||
if (baseTypeId == InvalidOid)
|
||||
baseTypeId = getBaseType(typeId);
|
||||
|
||||
ScanKeyData key[1];
|
||||
int nkeys = 0;
|
||||
SysScanDesc scan;
|
||||
Relation conRel;
|
||||
|
||||
tup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(typeId),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "coerce_type_constraints: failed to lookup type %u",
|
||||
typeId);
|
||||
typTup = (Form_pg_type) GETSTRUCT(tup);
|
||||
|
||||
/* Test for NOT NULL Constraint */
|
||||
if (typTup->typnotnull && notNull == NULL)
|
||||
notNull = pstrdup(NameStr(typTup->typname));
|
||||
|
||||
/* Add CHECK Constraints to domains */
|
||||
conRel = heap_openr(ConstraintRelationName, RowShareLock);
|
||||
|
||||
ScanKeyEntryInitialize(&key[nkeys++], 0x0,
|
||||
Anum_pg_constraint_contypid, F_OIDEQ,
|
||||
ObjectIdGetDatum(typeId));
|
||||
|
||||
scan = systable_beginscan(conRel, ConstraintTypidIndex, true,
|
||||
SnapshotNow, nkeys, key);
|
||||
|
||||
while (HeapTupleIsValid(conTup = systable_getnext(scan)))
|
||||
{
|
||||
Datum val;
|
||||
bool isNull;
|
||||
ConstraintTest *r = makeNode(ConstraintTest);
|
||||
Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
|
||||
|
||||
/* 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, "coerce_type_constraints: domain %s constraint %s has NULL conbin",
|
||||
NameStr(typTup->typname), NameStr(c->conname));
|
||||
|
||||
r->arg = (Expr *) arg;
|
||||
r->testtype = CONSTR_TEST_CHECK;
|
||||
r->name = NameStr(c->conname);
|
||||
r->domname = NameStr(typTup->typname);
|
||||
r->check_expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
|
||||
val)));
|
||||
|
||||
arg = (Node *) r;
|
||||
}
|
||||
|
||||
systable_endscan(scan);
|
||||
heap_close(conRel, RowShareLock);
|
||||
|
||||
if (typTup->typtype != 'd')
|
||||
{
|
||||
/* Not a domain, so done */
|
||||
ReleaseSysCache(tup);
|
||||
break;
|
||||
}
|
||||
|
||||
Assert(typmod < 0);
|
||||
|
||||
typeId = typTup->typbasetype;
|
||||
typmod = typTup->typtypmod;
|
||||
ReleaseSysCache(tup);
|
||||
}
|
||||
/* If it isn't a domain, return the node as it was passed in */
|
||||
if (baseTypeId == typeId)
|
||||
return arg;
|
||||
|
||||
/*
|
||||
* If domain applies a typmod to its base type, do length coercion.
|
||||
* If the domain applies a typmod to its base type, build the appropriate
|
||||
* coercion step. Mark it implicit for display purposes, because we don't
|
||||
* want it shown separately by ruleutils.c; but the isExplicit flag passed
|
||||
* to the conversion function depends on the manner in which the domain
|
||||
* coercion is invoked, so that the semantics of implicit and explicit
|
||||
* coercion differ. (Is that really the behavior we want?)
|
||||
*
|
||||
* NOTE: because we apply this as part of the fixed expression structure,
|
||||
* ALTER DOMAIN cannot alter the typtypmod. But it's unclear that that
|
||||
* would be safe to do anyway, without lots of knowledge about what the
|
||||
* base type thinks the typmod means.
|
||||
*/
|
||||
typmod = get_typtypmod(typeId);
|
||||
if (typmod >= 0)
|
||||
arg = coerce_type_typmod(arg, typeId, typmod, cformat);
|
||||
arg = coerce_type_typmod(arg, baseTypeId, typmod,
|
||||
COERCE_IMPLICIT_CAST,
|
||||
(cformat != COERCE_IMPLICIT_CAST));
|
||||
|
||||
/*
|
||||
* Only need to add one NOT NULL check regardless of how many domains
|
||||
* in the stack request it. The topmost domain that requested it is
|
||||
* used as the constraint name.
|
||||
* Now build the domain coercion node. This represents run-time checking
|
||||
* of any constraints currently attached to the domain. This also
|
||||
* ensures that the expression is properly labeled as to result type.
|
||||
*/
|
||||
if (notNull)
|
||||
{
|
||||
ConstraintTest *r = makeNode(ConstraintTest);
|
||||
result = makeNode(CoerceToDomain);
|
||||
result->arg = (Expr *) arg;
|
||||
result->resulttype = typeId;
|
||||
result->resulttypmod = -1; /* currently, always -1 for domains */
|
||||
result->coercionformat = cformat;
|
||||
|
||||
r->arg = (Expr *) arg;
|
||||
r->testtype = CONSTR_TEST_NOTNULL;
|
||||
r->name = "NOT NULL";
|
||||
r->domname = notNull;
|
||||
r->check_expr = NULL;
|
||||
|
||||
arg = (Node *) r;
|
||||
}
|
||||
|
||||
return arg;
|
||||
return (Node *) result;
|
||||
}
|
||||
|
||||
|
||||
@ -526,7 +454,7 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
|
||||
*/
|
||||
static Node *
|
||||
coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
|
||||
CoercionForm cformat)
|
||||
CoercionForm cformat, bool isExplicit)
|
||||
{
|
||||
Oid funcId;
|
||||
int nargs;
|
||||
@ -559,7 +487,7 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
|
||||
/* Pass it a boolean isExplicit parameter, too */
|
||||
cons = makeConst(BOOLOID,
|
||||
sizeof(bool),
|
||||
BoolGetDatum(cformat != COERCE_IMPLICIT_CAST),
|
||||
BoolGetDatum(isExplicit),
|
||||
false,
|
||||
true);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.141 2003/01/13 00:18:51 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.142 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -674,8 +674,8 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
case T_ArrayRef:
|
||||
case T_FieldSelect:
|
||||
case T_RelabelType:
|
||||
case T_ConstraintTest:
|
||||
case T_ConstraintTestValue:
|
||||
case T_CoerceToDomain:
|
||||
case T_CoerceToDomainValue:
|
||||
{
|
||||
result = (Node *) expr;
|
||||
break;
|
||||
@ -1017,11 +1017,11 @@ exprType(Node *expr)
|
||||
case T_BooleanTest:
|
||||
type = BOOLOID;
|
||||
break;
|
||||
case T_ConstraintTest:
|
||||
type = exprType((Node *) ((ConstraintTest *) expr)->arg);
|
||||
case T_CoerceToDomain:
|
||||
type = ((CoerceToDomain *) expr)->resulttype;
|
||||
break;
|
||||
case T_ConstraintTestValue:
|
||||
type = ((ConstraintTestValue *) expr)->typeId;
|
||||
case T_CoerceToDomainValue:
|
||||
type = ((CoerceToDomainValue *) expr)->typeId;
|
||||
break;
|
||||
case T_RangeVar:
|
||||
/*
|
||||
@ -1117,10 +1117,10 @@ exprTypmod(Node *expr)
|
||||
return typmod;
|
||||
}
|
||||
break;
|
||||
case T_ConstraintTest:
|
||||
return exprTypmod((Node *) ((ConstraintTest *) expr)->arg);
|
||||
case T_ConstraintTestValue:
|
||||
return ((ConstraintTestValue *) expr)->typeMod;
|
||||
case T_CoerceToDomain:
|
||||
return ((CoerceToDomain *) expr)->resulttypmod;
|
||||
case T_CoerceToDomainValue:
|
||||
return ((CoerceToDomainValue *) expr)->typeMod;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
* back to source text
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.133 2003/02/03 15:17:24 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.134 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@ -638,11 +638,11 @@ pg_get_constraintdef(PG_FUNCTION_ARGS)
|
||||
}
|
||||
appendStringInfo(&buf, "%s", string);
|
||||
|
||||
/* Add ON UPDATE and ON DELETE clauses */
|
||||
/* Add ON UPDATE and ON DELETE clauses, if needed */
|
||||
switch (conForm->confupdtype)
|
||||
{
|
||||
case FKCONSTR_ACTION_NOACTION:
|
||||
string = "";
|
||||
string = NULL; /* suppress default */
|
||||
break;
|
||||
case FKCONSTR_ACTION_RESTRICT:
|
||||
string = "RESTRICT";
|
||||
@ -659,16 +659,16 @@ pg_get_constraintdef(PG_FUNCTION_ARGS)
|
||||
default:
|
||||
elog(ERROR, "pg_get_constraintdef: Unknown confupdtype '%c' for constraint %u",
|
||||
conForm->confupdtype, constraintId);
|
||||
string = ""; /* keep compiler quiet */
|
||||
string = NULL; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
if (strlen(string) != 0)
|
||||
if (string)
|
||||
appendStringInfo(&buf, " ON UPDATE %s", string);
|
||||
|
||||
switch (conForm->confdeltype)
|
||||
{
|
||||
case FKCONSTR_ACTION_NOACTION:
|
||||
string = "";
|
||||
string = NULL; /* suppress default */
|
||||
break;
|
||||
case FKCONSTR_ACTION_RESTRICT:
|
||||
string = "RESTRICT";
|
||||
@ -685,10 +685,10 @@ pg_get_constraintdef(PG_FUNCTION_ARGS)
|
||||
default:
|
||||
elog(ERROR, "pg_get_constraintdef: Unknown confdeltype '%c' for constraint %u",
|
||||
conForm->confdeltype, constraintId);
|
||||
string = ""; /* keep compiler quiet */
|
||||
string = NULL; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
if (strlen(string) != 0)
|
||||
if (string)
|
||||
appendStringInfo(&buf, " ON DELETE %s", string);
|
||||
|
||||
if (conForm->condeferrable)
|
||||
@ -2252,19 +2252,34 @@ get_rule_expr(Node *node, deparse_context *context,
|
||||
}
|
||||
break;
|
||||
|
||||
case T_ConstraintTest:
|
||||
case T_CoerceToDomain:
|
||||
{
|
||||
ConstraintTest *ctest = (ConstraintTest *) node;
|
||||
CoerceToDomain *ctest = (CoerceToDomain *) node;
|
||||
Node *arg = (Node *) ctest->arg;
|
||||
|
||||
/*
|
||||
* We assume that the operations of the constraint node
|
||||
* need not be explicitly represented in the output.
|
||||
* Any implicit coercion at the top level of the argument
|
||||
* is presumably due to the domain's own internal typmod
|
||||
* coercion, so do not force it to be shown.
|
||||
*/
|
||||
get_rule_expr((Node *) ctest->arg, context, showimplicit);
|
||||
if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
|
||||
!showimplicit)
|
||||
{
|
||||
/* don't show the implicit cast */
|
||||
get_rule_expr(arg, context, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
appendStringInfoChar(buf, '(');
|
||||
get_rule_expr(arg, context, false);
|
||||
appendStringInfo(buf, ")::%s",
|
||||
format_type_with_typemod(ctest->resulttype,
|
||||
ctest->resulttypmod));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case T_ConstraintTestValue:
|
||||
case T_CoerceToDomainValue:
|
||||
appendStringInfo(buf, "VALUE");
|
||||
break;
|
||||
|
||||
@ -2444,7 +2459,8 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
|
||||
* the expression tree has a length-coercion node atop a type-coercion node.
|
||||
*
|
||||
* Note: avoid stripping a length-coercion node, since two successive
|
||||
* coercions to different lengths aren't a no-op.
|
||||
* coercions to different lengths aren't a no-op. Also, never strip a
|
||||
* CoerceToDomain node, even though it might be effectively just RelabelType.
|
||||
*/
|
||||
static Node *
|
||||
strip_type_coercion(Node *expr, Oid resultType)
|
||||
|
29
src/backend/utils/cache/lsyscache.c
vendored
29
src/backend/utils/cache/lsyscache.c
vendored
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.89 2003/01/15 19:35:44 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.90 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Eventually, the index information should go through here, too.
|
||||
@ -1012,6 +1012,33 @@ get_typstorage(Oid typid)
|
||||
return 'p';
|
||||
}
|
||||
|
||||
/*
|
||||
* get_typtypmod
|
||||
*
|
||||
* Given the type OID, return the typtypmod field (domain's typmod
|
||||
* for base type)
|
||||
*/
|
||||
int32
|
||||
get_typtypmod(Oid typid)
|
||||
{
|
||||
HeapTuple tp;
|
||||
|
||||
tp = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(typid),
|
||||
0, 0, 0);
|
||||
if (HeapTupleIsValid(tp))
|
||||
{
|
||||
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
|
||||
int32 result;
|
||||
|
||||
result = typtup->typtypmod;
|
||||
ReleaseSysCache(tp);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_typdefault
|
||||
* Given a type OID, return the type's default value, if any.
|
||||
|
@ -37,7 +37,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: catversion.h,v 1.174 2003/01/28 22:13:36 tgl Exp $
|
||||
* $Id: catversion.h,v 1.175 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 200301281
|
||||
#define CATALOG_VERSION_NO 200302031
|
||||
|
||||
#endif
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: typecmds.h,v 1.4 2003/01/09 18:00:24 tgl Exp $
|
||||
* $Id: typecmds.h,v 1.5 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -32,6 +32,8 @@ extern void AlterDomainAddConstraint(List *names, Node *constr);
|
||||
extern void AlterDomainDropConstraint(List *names, const char *constrName,
|
||||
DropBehavior behavior);
|
||||
|
||||
extern List *GetDomainConstraints(Oid typeOid);
|
||||
|
||||
extern void AlterTypeOwner(List *names, AclId newOwnerSysId);
|
||||
|
||||
#endif /* TYPECMDS_H */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: execnodes.h,v 1.92 2003/01/23 05:10:41 tgl Exp $
|
||||
* $Id: execnodes.h,v 1.93 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -114,7 +114,7 @@ typedef struct ExprContext
|
||||
Datum *ecxt_aggvalues; /* precomputed values for Aggref nodes */
|
||||
bool *ecxt_aggnulls; /* null flags for Aggref nodes */
|
||||
|
||||
/* Value to substitute for ConstraintTestValue nodes in expression */
|
||||
/* Value to substitute for CoerceToDomainValue nodes in expression */
|
||||
Datum domainValue_datum;
|
||||
bool domainValue_isNull;
|
||||
|
||||
@ -539,15 +539,37 @@ typedef struct CaseWhenState
|
||||
} CaseWhenState;
|
||||
|
||||
/* ----------------
|
||||
* ConstraintTestState node
|
||||
* CoerceToDomainState node
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct ConstraintTestState
|
||||
typedef struct CoerceToDomainState
|
||||
{
|
||||
ExprState xprstate;
|
||||
ExprState *arg; /* input expression */
|
||||
ExprState *check_expr; /* for CHECK test, a boolean expression */
|
||||
} ConstraintTestState;
|
||||
/* Cached list of constraints that need to be checked */
|
||||
List *constraints; /* list of DomainConstraintState nodes */
|
||||
} CoerceToDomainState;
|
||||
|
||||
/*
|
||||
* DomainConstraintState - one item to check during CoerceToDomain
|
||||
*
|
||||
* Note: this is just a Node, and not an ExprState, because it has no
|
||||
* corresponding Expr to link to. Nonetheless it is part of an ExprState
|
||||
* tree, so we give it a name following the xxxState convention.
|
||||
*/
|
||||
typedef enum DomainConstraintType
|
||||
{
|
||||
DOM_CONSTRAINT_NOTNULL,
|
||||
DOM_CONSTRAINT_CHECK
|
||||
} DomainConstraintType;
|
||||
|
||||
typedef struct DomainConstraintState
|
||||
{
|
||||
NodeTag type;
|
||||
DomainConstraintType constrainttype; /* constraint type */
|
||||
char *name; /* name of constraint (for error msgs) */
|
||||
ExprState *check_expr; /* for CHECK, a boolean expression */
|
||||
} DomainConstraintState;
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodes.h,v 1.135 2003/01/20 18:55:00 tgl Exp $
|
||||
* $Id: nodes.h,v 1.136 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -114,8 +114,8 @@ typedef enum NodeTag
|
||||
T_CaseWhen,
|
||||
T_NullTest,
|
||||
T_BooleanTest,
|
||||
T_ConstraintTest,
|
||||
T_ConstraintTestValue,
|
||||
T_CoerceToDomain,
|
||||
T_CoerceToDomainValue,
|
||||
T_TargetEntry,
|
||||
T_RangeTblRef,
|
||||
T_JoinExpr,
|
||||
@ -136,7 +136,8 @@ typedef enum NodeTag
|
||||
T_SubPlanState,
|
||||
T_CaseExprState,
|
||||
T_CaseWhenState,
|
||||
T_ConstraintTestState,
|
||||
T_CoerceToDomainState,
|
||||
T_DomainConstraintState,
|
||||
|
||||
/*
|
||||
* TAGS FOR PLANNER NODES (relation.h)
|
||||
|
@ -10,7 +10,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: primnodes.h,v 1.77 2003/01/10 21:08:15 tgl Exp $
|
||||
* $Id: primnodes.h,v 1.78 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -578,28 +578,22 @@ typedef struct BooleanTest
|
||||
} BooleanTest;
|
||||
|
||||
/*
|
||||
* ConstraintTest
|
||||
* CoerceToDomain
|
||||
*
|
||||
* ConstraintTest represents the operation of testing a value to see whether
|
||||
* it meets a constraint. If so, the input value is returned as the result;
|
||||
* if not, an error is raised.
|
||||
* CoerceToDomain represents the operation of coercing a value to a domain
|
||||
* type. At runtime (and not before) the precise set of constraints to be
|
||||
* checked will be determined. If the value passes, it is returned as the
|
||||
* result; if not, an error is raised. Note that this is equivalent to
|
||||
* RelabelType in the scenario where no constraints are applied.
|
||||
*/
|
||||
|
||||
typedef enum ConstraintTestType
|
||||
{
|
||||
CONSTR_TEST_NOTNULL,
|
||||
CONSTR_TEST_CHECK
|
||||
} ConstraintTestType;
|
||||
|
||||
typedef struct ConstraintTest
|
||||
typedef struct CoerceToDomain
|
||||
{
|
||||
Expr xpr;
|
||||
Expr *arg; /* input expression */
|
||||
ConstraintTestType testtype; /* test type */
|
||||
char *name; /* name of constraint (for error msgs) */
|
||||
char *domname; /* name of domain (for error messages) */
|
||||
Expr *check_expr; /* for CHECK test, a boolean expression */
|
||||
} ConstraintTest;
|
||||
Oid resulttype; /* domain type ID (result type) */
|
||||
int32 resulttypmod; /* output typmod (currently always -1) */
|
||||
CoercionForm coercionformat; /* how to display this node */
|
||||
} CoerceToDomain;
|
||||
|
||||
/*
|
||||
* Placeholder node for the value to be processed by a domain's check
|
||||
@ -610,12 +604,12 @@ typedef struct ConstraintTest
|
||||
* the domain itself. This is because we shouldn't consider the value to
|
||||
* be a member of the domain if we haven't yet checked its constraints.
|
||||
*/
|
||||
typedef struct ConstraintTestValue
|
||||
typedef struct CoerceToDomainValue
|
||||
{
|
||||
Expr xpr;
|
||||
Oid typeId; /* type for substituted value */
|
||||
int32 typeMod; /* typemod for substituted value */
|
||||
} ConstraintTestValue;
|
||||
} CoerceToDomainValue;
|
||||
|
||||
|
||||
/*
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: parse_coerce.h,v 1.48 2002/10/24 22:09:00 tgl Exp $
|
||||
* $Id: parse_coerce.h,v 1.49 2003/02/03 21:15:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -45,8 +45,8 @@ extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
|
||||
CoercionContext ccontext);
|
||||
extern Node *coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
|
||||
CoercionContext ccontext, CoercionForm cformat);
|
||||
extern Node *coerce_type_constraints(Node *arg, Oid typeId,
|
||||
CoercionForm cformat);
|
||||
extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, Oid typeId,
|
||||
CoercionForm cformat);
|
||||
|
||||
extern Node *coerce_to_boolean(Node *node, const char *constructName);
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: lsyscache.h,v 1.66 2003/01/15 19:35:47 tgl Exp $
|
||||
* $Id: lsyscache.h,v 1.67 2003/02/03 21:15:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -54,6 +54,7 @@ extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
|
||||
extern void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
|
||||
char *typalign);
|
||||
extern char get_typstorage(Oid typid);
|
||||
extern int32 get_typtypmod(Oid typid);
|
||||
extern Node *get_typdefault(Oid typid);
|
||||
extern char get_typtype(Oid typid);
|
||||
extern Oid get_typ_typrelid(Oid typid);
|
||||
|
@ -3,7 +3,7 @@
|
||||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.77 2003/01/21 22:06:12 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.78 2003/02/03 21:15:45 tgl Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@ -3634,6 +3634,9 @@ exec_simple_check_node(Node *node)
|
||||
case T_BooleanTest:
|
||||
return exec_simple_check_node((Node *) ((BooleanTest *) node)->arg);
|
||||
|
||||
case T_CoerceToDomain:
|
||||
return exec_simple_check_node((Node *) ((CoerceToDomain *) node)->arg);
|
||||
|
||||
case T_List:
|
||||
{
|
||||
List *expr = (List *) node;
|
||||
|
@ -257,14 +257,49 @@ ERROR: ALTER DOMAIN: Relation "domcontest" attribute "col1" contains values tha
|
||||
alter domain con add constraint t check (VALUE < 34);
|
||||
alter domain con add check (VALUE > 0);
|
||||
insert into domcontest values (-5); -- fails
|
||||
ERROR: ExecEvalConstraintTest: Domain con constraint $1 failed
|
||||
ERROR: ExecEvalCoerceToDomain: Domain con constraint $1 failed
|
||||
insert into domcontest values (42); -- fails
|
||||
ERROR: ExecEvalConstraintTest: Domain con constraint t failed
|
||||
ERROR: ExecEvalCoerceToDomain: Domain con constraint t failed
|
||||
insert into domcontest values (5);
|
||||
alter domain con drop constraint t;
|
||||
insert into domcontest values (-5); --fails
|
||||
ERROR: ExecEvalConstraintTest: Domain con constraint $1 failed
|
||||
ERROR: ExecEvalCoerceToDomain: Domain con constraint $1 failed
|
||||
insert into domcontest values (42);
|
||||
-- Confirm ALTER DOMAIN with RULES.
|
||||
create table domtab (col1 integer);
|
||||
create domain dom as integer;
|
||||
create view domview as select cast(col1 as dom) from domtab;
|
||||
insert into domtab (col1) values (null);
|
||||
insert into domtab (col1) values (5);
|
||||
select * from domview;
|
||||
col1
|
||||
------
|
||||
|
||||
5
|
||||
(2 rows)
|
||||
|
||||
alter domain dom set not null;
|
||||
select * from domview; -- fail
|
||||
ERROR: Domain dom does not allow NULL values
|
||||
alter domain dom drop not null;
|
||||
select * from domview;
|
||||
col1
|
||||
------
|
||||
|
||||
5
|
||||
(2 rows)
|
||||
|
||||
alter domain dom add constraint domchkgt6 check(value > 6);
|
||||
select * from domview; --fail
|
||||
ERROR: ExecEvalCoerceToDomain: Domain dom constraint domchkgt6 failed
|
||||
alter domain dom drop constraint domchkgt6 restrict;
|
||||
select * from domview;
|
||||
col1
|
||||
------
|
||||
|
||||
5
|
||||
(2 rows)
|
||||
|
||||
-- cleanup
|
||||
drop domain ddef1 restrict;
|
||||
drop domain ddef2 restrict;
|
||||
|
@ -224,6 +224,26 @@ alter domain con drop constraint t;
|
||||
insert into domcontest values (-5); --fails
|
||||
insert into domcontest values (42);
|
||||
|
||||
-- Confirm ALTER DOMAIN with RULES.
|
||||
create table domtab (col1 integer);
|
||||
create domain dom as integer;
|
||||
create view domview as select cast(col1 as dom) from domtab;
|
||||
insert into domtab (col1) values (null);
|
||||
insert into domtab (col1) values (5);
|
||||
select * from domview;
|
||||
|
||||
alter domain dom set not null;
|
||||
select * from domview; -- fail
|
||||
|
||||
alter domain dom drop not null;
|
||||
select * from domview;
|
||||
|
||||
alter domain dom add constraint domchkgt6 check(value > 6);
|
||||
select * from domview; --fail
|
||||
|
||||
alter domain dom drop constraint domchkgt6 restrict;
|
||||
select * from domview;
|
||||
|
||||
-- cleanup
|
||||
drop domain ddef1 restrict;
|
||||
drop domain ddef2 restrict;
|
||||
|
Loading…
x
Reference in New Issue
Block a user