Add DOMAIN check constraints.
Rod Taylor
This commit is contained in:
parent
2986aa6a66
commit
6b603e67dc
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_domain.sgml,v 1.6 2002/09/20 03:39:15 momjian Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_domain.sgml,v 1.7 2002/11/15 02:50:05 momjian Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
@ -200,16 +200,6 @@ CREATE TABLE countrylist (id INT4, country country_code);
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="SQL-CREATEDOMAIN-compatibility">
|
||||
<title>Compatibility</title>
|
||||
|
||||
<para>
|
||||
SQL99 defines CREATE DOMAIN, but says that the only allowed constraint
|
||||
type is CHECK constraints. CHECK constraints for domains are not yet
|
||||
supported by <productname>PostgreSQL</productname>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="SQL-CREATEDOMAIN-see-also">
|
||||
<title>See Also</title>
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.234 2002/11/11 22:19:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.235 2002/11/15 02:50:05 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -1500,7 +1500,8 @@ AddRelationRawConstraints(Relation rel,
|
||||
|
||||
ccname = cdef->name;
|
||||
/* Check against pre-existing constraints */
|
||||
if (ConstraintNameIsUsed(RelationGetRelid(rel),
|
||||
if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
|
||||
RelationGetRelid(rel),
|
||||
RelationGetNamespace(rel),
|
||||
ccname))
|
||||
elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
|
||||
@ -1534,7 +1535,8 @@ AddRelationRawConstraints(Relation rel,
|
||||
* pre-existing constraints, nor with any auto-generated
|
||||
* names so far.
|
||||
*/
|
||||
ccname = GenerateConstraintName(RelationGetRelid(rel),
|
||||
ccname = GenerateConstraintName(CONSTRAINT_RELATION,
|
||||
RelationGetRelid(rel),
|
||||
RelationGetNamespace(rel),
|
||||
&constr_name_ctr);
|
||||
|
||||
@ -1565,7 +1567,7 @@ AddRelationRawConstraints(Relation rel,
|
||||
/*
|
||||
* Transform raw parsetree to executable expression.
|
||||
*/
|
||||
expr = transformExpr(pstate, cdef->raw_expr);
|
||||
expr = transformExpr(pstate, cdef->raw_expr, NULL);
|
||||
|
||||
/*
|
||||
* Make sure it yields a boolean result.
|
||||
@ -1694,7 +1696,7 @@ cookDefault(ParseState *pstate,
|
||||
/*
|
||||
* Transform raw parsetree to executable expression.
|
||||
*/
|
||||
expr = transformExpr(pstate, raw_default);
|
||||
expr = transformExpr(pstate, raw_default, NULL);
|
||||
|
||||
/*
|
||||
* Make sure default expr does not refer to any vars.
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.7 2002/09/22 00:37:09 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.8 2002/11/15 02:50:05 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -190,6 +190,19 @@ CreateConstraintEntry(const char *constraintName,
|
||||
}
|
||||
}
|
||||
|
||||
if (OidIsValid(domainId))
|
||||
{
|
||||
/*
|
||||
* Register auto dependency from constraint to owning domain
|
||||
*/
|
||||
ObjectAddress domobject;
|
||||
|
||||
domobject.classId = RelOid_pg_type;
|
||||
domobject.objectId = domainId;
|
||||
|
||||
recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
|
||||
}
|
||||
|
||||
if (OidIsValid(foreignRelId))
|
||||
{
|
||||
/*
|
||||
@ -262,7 +275,7 @@ CreateConstraintEntry(const char *constraintName,
|
||||
* this test is not very meaningful.
|
||||
*/
|
||||
bool
|
||||
ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
|
||||
ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, const char *cname)
|
||||
{
|
||||
bool found;
|
||||
Relation conDesc;
|
||||
@ -280,7 +293,7 @@ ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
|
||||
|
||||
ScanKeyEntryInitialize(&skey[1], 0x0,
|
||||
Anum_pg_constraint_connamespace, F_OIDEQ,
|
||||
ObjectIdGetDatum(relNamespace));
|
||||
ObjectIdGetDatum(objNamespace));
|
||||
|
||||
conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
|
||||
SnapshotNow, 2, skey);
|
||||
@ -289,7 +302,12 @@ ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
|
||||
{
|
||||
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
|
||||
|
||||
if (con->conrelid == relId)
|
||||
if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
@ -314,7 +332,7 @@ ConstraintNameIsUsed(Oid relId, Oid relNamespace, const char *cname)
|
||||
* someone else might choose the same name concurrently!
|
||||
*/
|
||||
char *
|
||||
GenerateConstraintName(Oid relId, Oid relNamespace, int *counter)
|
||||
GenerateConstraintName(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, int *counter)
|
||||
{
|
||||
bool found;
|
||||
Relation conDesc;
|
||||
@ -347,7 +365,7 @@ GenerateConstraintName(Oid relId, Oid relNamespace, int *counter)
|
||||
|
||||
ScanKeyEntryInitialize(&skey[1], 0x0,
|
||||
Anum_pg_constraint_connamespace, F_OIDEQ,
|
||||
ObjectIdGetDatum(relNamespace));
|
||||
ObjectIdGetDatum(objNamespace));
|
||||
|
||||
conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
|
||||
SnapshotNow, 2, skey);
|
||||
@ -356,7 +374,12 @@ GenerateConstraintName(Oid relId, Oid relNamespace, int *counter)
|
||||
{
|
||||
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
|
||||
|
||||
if (con->conrelid == relId)
|
||||
if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
@ -415,10 +438,13 @@ RemoveConstraintById(Oid conId)
|
||||
con = (Form_pg_constraint) GETSTRUCT(tup);
|
||||
|
||||
/*
|
||||
* If the constraint is for a relation, open and exclusive-lock the
|
||||
* relation it's for.
|
||||
* If the constraint is for a relation, open and exclusive-lock
|
||||
* the relation it's for.
|
||||
*
|
||||
* XXX not clear what we should lock, if anything, for other constraints.
|
||||
* If the constraint is for a domain, open and lock the pg_type entry
|
||||
* tye constraint is used on.
|
||||
*
|
||||
* XXX not clear what we should lock, if anything, for assert constraints.
|
||||
*/
|
||||
if (OidIsValid(con->conrelid))
|
||||
{
|
||||
@ -463,6 +489,34 @@ RemoveConstraintById(Oid conId)
|
||||
/* Keep lock on constraint's rel until end of xact */
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
/* Lock the domain row in pg_type */
|
||||
else if (OidIsValid(con->contypid))
|
||||
{
|
||||
Relation typRel;
|
||||
HeapTuple typTup;
|
||||
ScanKeyData typKey[1];
|
||||
SysScanDesc typScan;
|
||||
|
||||
typRel = heap_openr(TypeRelationName, RowExclusiveLock);
|
||||
|
||||
ScanKeyEntryInitialize(&typKey[0], 0x0,
|
||||
Anum_pg_constraint_contypid, F_OIDEQ,
|
||||
ObjectIdGetDatum(con->contypid));
|
||||
|
||||
typScan = systable_beginscan(typRel, TypeOidIndex, true,
|
||||
SnapshotNow, 1, typKey);
|
||||
|
||||
typTup = systable_getnext(typScan);
|
||||
|
||||
if (!HeapTupleIsValid(typTup))
|
||||
elog(ERROR, "RemoveConstraintById: Type %d does not exist",
|
||||
con->contypid);
|
||||
|
||||
systable_endscan(typScan);
|
||||
|
||||
/* Keep lock on domain type until end of xact */
|
||||
heap_close(typRel, NoLock);
|
||||
}
|
||||
|
||||
/* Fry the constraint itself */
|
||||
simple_heap_delete(conDesc, &tup->t_self);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.53 2002/11/11 22:19:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.54 2002/11/15 02:50:05 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -2632,14 +2632,16 @@ AlterTableAddConstraint(Oid myrelid, bool recurse,
|
||||
*/
|
||||
if (constr->name)
|
||||
{
|
||||
if (ConstraintNameIsUsed(RelationGetRelid(rel),
|
||||
if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
|
||||
RelationGetRelid(rel),
|
||||
RelationGetNamespace(rel),
|
||||
constr->name))
|
||||
elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
|
||||
constr->name, RelationGetRelationName(rel));
|
||||
}
|
||||
else
|
||||
constr->name = GenerateConstraintName(RelationGetRelid(rel),
|
||||
constr->name = GenerateConstraintName(CONSTRAINT_RELATION,
|
||||
RelationGetRelid(rel),
|
||||
RelationGetNamespace(rel),
|
||||
&counter);
|
||||
|
||||
@ -2668,7 +2670,8 @@ AlterTableAddConstraint(Oid myrelid, bool recurse,
|
||||
*/
|
||||
if (fkconstraint->constr_name)
|
||||
{
|
||||
if (ConstraintNameIsUsed(RelationGetRelid(rel),
|
||||
if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
|
||||
RelationGetRelid(rel),
|
||||
RelationGetNamespace(rel),
|
||||
fkconstraint->constr_name))
|
||||
elog(ERROR, "constraint \"%s\" already exists for relation \"%s\"",
|
||||
@ -2676,7 +2679,8 @@ AlterTableAddConstraint(Oid myrelid, bool recurse,
|
||||
RelationGetRelationName(rel));
|
||||
}
|
||||
else
|
||||
fkconstraint->constr_name = GenerateConstraintName(RelationGetRelid(rel),
|
||||
fkconstraint->constr_name = GenerateConstraintName(CONSTRAINT_RELATION,
|
||||
RelationGetRelid(rel),
|
||||
RelationGetNamespace(rel),
|
||||
&counter);
|
||||
|
||||
@ -2734,7 +2738,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr)
|
||||
/*
|
||||
* Convert the A_EXPR in raw_expr into an EXPR
|
||||
*/
|
||||
expr = transformExpr(pstate, constr->raw_expr);
|
||||
expr = transformExpr(pstate, constr->raw_expr, NULL);
|
||||
|
||||
/*
|
||||
* Make sure it yields a boolean result.
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.16 2002/11/11 22:19:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.17 2002/11/15 02:50:06 momjian Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
@ -36,10 +36,17 @@
|
||||
#include "catalog/dependency.h"
|
||||
#include "catalog/heap.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_constraint.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/defrem.h"
|
||||
#include "commands/tablecmds.h"
|
||||
#include "miscadmin.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"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/acl.h"
|
||||
@ -406,7 +413,8 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
List *listptr;
|
||||
Oid basetypeoid;
|
||||
Oid domainoid;
|
||||
Form_pg_type baseType;
|
||||
Form_pg_type baseType;
|
||||
int counter = 0;
|
||||
|
||||
/* Convert list of names to a name and namespace */
|
||||
domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
|
||||
@ -484,17 +492,21 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
basetypelem = baseType->typelem;
|
||||
|
||||
/*
|
||||
* Run through constraints manually to avoid the additional processing
|
||||
* conducted by DefineRelation() and friends.
|
||||
*
|
||||
* Besides, we don't want any constraints to be cooked. We'll do that
|
||||
* when the table is created via MergeDomainAttributes().
|
||||
* Run through constraints manually to avoid the additional
|
||||
* processing conducted by DefineRelation() and friends.
|
||||
*/
|
||||
foreach(listptr, schema)
|
||||
{
|
||||
Constraint *colDef = lfirst(listptr);
|
||||
Node *newConstraint = lfirst(listptr);
|
||||
Constraint *colDef;
|
||||
ParseState *pstate;
|
||||
|
||||
/* Prior to processing, confirm that it is not a foreign key constraint */
|
||||
if (nodeTag(newConstraint) == T_FkConstraint)
|
||||
elog(ERROR, "CREATE DOMAIN / FOREIGN KEY constraints not supported");
|
||||
|
||||
colDef = (Constraint *) newConstraint;
|
||||
|
||||
switch (colDef->contype)
|
||||
{
|
||||
/*
|
||||
@ -546,26 +558,26 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
|
||||
typNotNull = false;
|
||||
nullDefined = true;
|
||||
break;
|
||||
break;
|
||||
|
||||
case CONSTR_UNIQUE:
|
||||
elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported");
|
||||
break;
|
||||
case CONSTR_UNIQUE:
|
||||
elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported");
|
||||
break;
|
||||
|
||||
case CONSTR_PRIMARY:
|
||||
elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes not supported");
|
||||
break;
|
||||
case CONSTR_PRIMARY:
|
||||
elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes not supported");
|
||||
break;
|
||||
|
||||
case CONSTR_CHECK:
|
||||
elog(ERROR, "DefineDomain: CHECK Constraints not supported");
|
||||
break;
|
||||
/* Check constraints are handled after domain creation */
|
||||
case CONSTR_CHECK:
|
||||
break;
|
||||
|
||||
case CONSTR_ATTR_DEFERRABLE:
|
||||
case CONSTR_ATTR_NOT_DEFERRABLE:
|
||||
case CONSTR_ATTR_DEFERRED:
|
||||
case CONSTR_ATTR_IMMEDIATE:
|
||||
elog(ERROR, "DefineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
|
||||
break;
|
||||
case CONSTR_ATTR_DEFERRABLE:
|
||||
case CONSTR_ATTR_NOT_DEFERRABLE:
|
||||
case CONSTR_ATTR_DEFERRED:
|
||||
case CONSTR_ATTR_IMMEDIATE:
|
||||
elog(ERROR, "DefineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "DefineDomain: unrecognized constraint node type");
|
||||
@ -591,12 +603,139 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
basetypeoid, /* base type ID */
|
||||
defaultValue, /* default type value (text) */
|
||||
defaultValueBin, /* default type value (binary) */
|
||||
byValue, /* passed by value */
|
||||
alignment, /* required alignment */
|
||||
storage, /* TOAST strategy */
|
||||
stmt->typename->typmod, /* typeMod value */
|
||||
typNDims, /* Array dimensions for base type */
|
||||
typNotNull); /* Type NOT NULL */
|
||||
byValue, /* passed by value */
|
||||
alignment, /* required alignment */
|
||||
storage, /* TOAST strategy */
|
||||
stmt->typename->typmod, /* typeMod value */
|
||||
typNDims, /* Array dimensions for base type */
|
||||
typNotNull); /* Type NOT NULL */
|
||||
|
||||
/*
|
||||
* Process constraints which refer to the domain ID returned by TypeCreate
|
||||
*/
|
||||
foreach(listptr, schema)
|
||||
{
|
||||
Constraint *constr = lfirst(listptr);
|
||||
ParseState *pstate;
|
||||
|
||||
switch (constr->contype)
|
||||
{
|
||||
case CONSTR_CHECK:
|
||||
{
|
||||
Node *expr;
|
||||
char *ccsrc;
|
||||
char *ccbin;
|
||||
ConstraintTestValue *domVal;
|
||||
|
||||
/*
|
||||
* Assign or validate constraint name
|
||||
*/
|
||||
if (constr->name)
|
||||
{
|
||||
if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
|
||||
domainoid,
|
||||
domainNamespace,
|
||||
constr->name))
|
||||
elog(ERROR, "constraint \"%s\" already exists for domain \"%s\"",
|
||||
constr->name,
|
||||
domainName);
|
||||
}
|
||||
else
|
||||
constr->name = GenerateConstraintName(CONSTRAINT_DOMAIN,
|
||||
domainoid,
|
||||
domainNamespace,
|
||||
&counter);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
domVal = makeNode(ConstraintTestValue);
|
||||
domVal->typeId = basetypeoid;
|
||||
domVal->typeMod = stmt->typename->typmod;
|
||||
|
||||
expr = transformExpr(pstate, constr->raw_expr, domVal);
|
||||
|
||||
/*
|
||||
* Domains don't allow var clauses
|
||||
*/
|
||||
if (contain_var_clause(expr))
|
||||
elog(ERROR, "cannot use column references in domain CHECK clause");
|
||||
|
||||
/*
|
||||
* Make sure it yields a boolean result.
|
||||
*/
|
||||
expr = coerce_to_boolean(expr, "CHECK");
|
||||
|
||||
/*
|
||||
* Make sure no outside relations are
|
||||
* referred to.
|
||||
*/
|
||||
if (length(pstate->p_rtable) != 0)
|
||||
elog(ERROR, "Relations cannot be referenced in domain CHECK constraint");
|
||||
|
||||
/*
|
||||
* No subplans or aggregates, either...
|
||||
*/
|
||||
if (contain_subplans(expr))
|
||||
elog(ERROR, "cannot use subselect in CHECK constraint expression");
|
||||
if (contain_agg_clause(expr))
|
||||
elog(ERROR, "cannot use aggregate function in CHECK constraint expression");
|
||||
|
||||
/*
|
||||
* Might as well try to reduce any constant expressions.
|
||||
*/
|
||||
expr = eval_const_expressions(expr);
|
||||
|
||||
/*
|
||||
* Must fix opids in operator clauses.
|
||||
*/
|
||||
fix_opids(expr);
|
||||
|
||||
ccbin = nodeToString(expr);
|
||||
|
||||
/*
|
||||
* Deparse it. Since VARNOs aren't allowed in domain
|
||||
* constraints, relation context isn't required as anything
|
||||
* other than a shell.
|
||||
*/
|
||||
ccsrc = deparse_expression(expr,
|
||||
deparse_context_for(domainName,
|
||||
InvalidOid),
|
||||
false, false);
|
||||
|
||||
/* Write the constraint */
|
||||
CreateConstraintEntry(constr->name, /* Constraint Name */
|
||||
domainNamespace, /* namespace */
|
||||
CONSTRAINT_CHECK, /* Constraint Type */
|
||||
false, /* Is Deferrable */
|
||||
false, /* Is Deferred */
|
||||
InvalidOid, /* not a relation constraint */
|
||||
NULL,
|
||||
0,
|
||||
domainoid, /* domain constraint */
|
||||
InvalidOid, /* Foreign key fields */
|
||||
NULL,
|
||||
0,
|
||||
' ',
|
||||
' ',
|
||||
' ',
|
||||
InvalidOid,
|
||||
expr, /* Tree form check constraint */
|
||||
ccbin, /* Binary form check constraint */
|
||||
ccsrc); /* Source form check constraint */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add any dependencies needed for the default expression.
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.108 2002/09/04 20:31:17 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.109 2002/11/15 02:50:06 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -72,6 +72,9 @@ static Datum ExecEvalBooleanTest(BooleanTest *btest, ExprContext *econtext,
|
||||
static Datum ExecEvalConstraintTest(ConstraintTest *constraint,
|
||||
ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalConstraintTestValue(ConstraintTestValue *conVal,
|
||||
ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
|
||||
|
||||
/*----------
|
||||
@ -1551,6 +1554,23 @@ ExecEvalBooleanTest(BooleanTest *btest,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ExecEvalConstraintTestValue
|
||||
*
|
||||
* Return the value stored by constraintTest.
|
||||
*/
|
||||
static Datum
|
||||
ExecEvalConstraintTestValue(ConstraintTestValue *conVal, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone)
|
||||
{
|
||||
/*
|
||||
* If the Datum hasn't been set, then it's ExecEvalConstraintTest
|
||||
* hasn't been called.
|
||||
*/
|
||||
*isNull = econtext->domainValue_isNull;
|
||||
return econtext->domainValue_datum;
|
||||
}
|
||||
|
||||
/*
|
||||
* ExecEvalConstraintTest
|
||||
*
|
||||
@ -1571,11 +1591,22 @@ ExecEvalConstraintTest(ConstraintTest *constraint, ExprContext *econtext,
|
||||
case CONSTR_TEST_NOTNULL:
|
||||
if (*isNull)
|
||||
elog(ERROR, "Domain %s does not allow NULL values",
|
||||
constraint->name);
|
||||
constraint->domname);
|
||||
break;
|
||||
case CONSTR_TEST_CHECK:
|
||||
/* TODO: Add CHECK Constraints to domains */
|
||||
elog(ERROR, "Domain CHECK Constraints not yet implemented");
|
||||
{
|
||||
Datum conResult;
|
||||
|
||||
/* Var with attnum == UnassignedAttrNum uses the result */
|
||||
econtext->domainValue_datum = result;
|
||||
econtext->domainValue_isNull = *isNull;
|
||||
|
||||
conResult = ExecEvalExpr(constraint->check_expr, econtext, isNull, isDone);
|
||||
|
||||
if (!DatumGetBool(conResult))
|
||||
elog(ERROR, "Domain %s constraint %s failed",
|
||||
constraint->name, constraint->domname);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "ExecEvalConstraintTest: Constraint type unknown");
|
||||
@ -1777,7 +1808,12 @@ ExecEvalExpr(Node *expression,
|
||||
isNull,
|
||||
isDone);
|
||||
break;
|
||||
|
||||
case T_ConstraintTestValue:
|
||||
retDatum = ExecEvalConstraintTestValue((ConstraintTestValue *) expression,
|
||||
econtext,
|
||||
isNull,
|
||||
isDone);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "ExecEvalExpr: unknown expression type %d",
|
||||
nodeTag(expression));
|
||||
|
@ -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.217 2002/11/11 22:19:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.218 2002/11/15 02:50:06 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1056,11 +1056,35 @@ _copyConstraintTest(ConstraintTest *from)
|
||||
newnode->testtype = from->testtype;
|
||||
if (from->name)
|
||||
newnode->name = pstrdup(from->name);
|
||||
if (from->domname)
|
||||
newnode->domname = pstrdup(from->domname);
|
||||
Node_Copy(from, newnode, check_expr);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static ConstraintTestValue *
|
||||
_copyConstraintTestValue(ConstraintTestValue *from)
|
||||
{
|
||||
ConstraintTestValue *newnode = makeNode(ConstraintTestValue);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
newnode->typeId = from->typeId;
|
||||
newnode->typeMod = from->typeMod;
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static DomainConstraintValue *
|
||||
_copyDomainConstraintValue(DomainConstraintValue *from)
|
||||
{
|
||||
DomainConstraintValue *newnode = makeNode(DomainConstraintValue);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static ArrayRef *
|
||||
_copyArrayRef(ArrayRef *from)
|
||||
{
|
||||
@ -3252,6 +3276,9 @@ copyObject(void *from)
|
||||
case T_ConstraintTest:
|
||||
retval = _copyConstraintTest(from);
|
||||
break;
|
||||
case T_ConstraintTestValue:
|
||||
retval = _copyConstraintTestValue(from);
|
||||
break;
|
||||
case T_FkConstraint:
|
||||
retval = _copyFkConstraint(from);
|
||||
break;
|
||||
@ -3264,6 +3291,9 @@ copyObject(void *from)
|
||||
case T_InsertDefault:
|
||||
retval = _copyInsertDefault(from);
|
||||
break;
|
||||
case T_DomainConstraintValue:
|
||||
retval = _copyDomainConstraintValue(from);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "copyObject: don't know how to copy node type %d",
|
||||
|
@ -20,7 +20,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.163 2002/11/11 22:19:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.164 2002/11/15 02:50:06 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1971,15 +1971,32 @@ _equalConstraintTest(ConstraintTest *a, ConstraintTest *b)
|
||||
return false;
|
||||
if (!equalstr(a->name, b->name))
|
||||
return false;
|
||||
if (!equalstr(a->domname, b->domname))
|
||||
return false;
|
||||
if (!equal(a->check_expr, b->check_expr))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalConstraintTestValue(ConstraintTestValue *a, ConstraintTestValue *b)
|
||||
{
|
||||
if (a->typeId != b->typeId)
|
||||
return false;
|
||||
if (a->typeMod != b->typeMod)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalDomainConstraintValue(DomainConstraintValue *a, DomainConstraintValue *b)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stuff from pg_list.h
|
||||
*/
|
||||
|
||||
static bool
|
||||
_equalValue(Value *a, Value *b)
|
||||
{
|
||||
@ -2438,6 +2455,9 @@ equal(void *a, void *b)
|
||||
case T_ConstraintTest:
|
||||
retval = _equalConstraintTest(a, b);
|
||||
break;
|
||||
case T_ConstraintTestValue:
|
||||
retval = _equalConstraintTestValue(a, b);
|
||||
break;
|
||||
case T_FkConstraint:
|
||||
retval = _equalFkConstraint(a, b);
|
||||
break;
|
||||
@ -2450,6 +2470,9 @@ equal(void *a, void *b)
|
||||
case T_InsertDefault:
|
||||
retval = _equalInsertDefault(a, b);
|
||||
break;
|
||||
case T_DomainConstraintValue:
|
||||
retval = _equalDomainConstraintValue(a, b);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(WARNING, "equal: don't know whether nodes of type %d are equal",
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.179 2002/11/11 22:19:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.180 2002/11/15 02:50:07 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every (plan) node in POSTGRES has an associated "out" routine which
|
||||
@ -1525,10 +1525,32 @@ _outConstraintTest(StringInfo str, ConstraintTest *node)
|
||||
appendStringInfo(str, " :testtype %d :name ",
|
||||
(int) node->testtype);
|
||||
_outToken(str, node->name);
|
||||
appendStringInfo(str, " :domain ");
|
||||
_outToken(str, node->domname);
|
||||
appendStringInfo(str, " :check_expr ");
|
||||
_outNode(str, node->check_expr);
|
||||
}
|
||||
|
||||
/*
|
||||
* ConstraintTestValue
|
||||
*/
|
||||
static void
|
||||
_outConstraintTestValue(StringInfo str, ConstraintTestValue *node)
|
||||
{
|
||||
appendStringInfo(str, " CONSTRAINTTESTVALUE :typeid %u :typemod %d ",
|
||||
node->typeId,
|
||||
node->typeMod);
|
||||
}
|
||||
|
||||
/*
|
||||
* DomainConstraintValue
|
||||
*/
|
||||
static void
|
||||
_outDomainConstraintValue(StringInfo str, DomainConstraintValue *node)
|
||||
{
|
||||
appendStringInfo(str, " DOMAINCONSTRAINTVALUE ");
|
||||
}
|
||||
|
||||
/*
|
||||
* _outNode -
|
||||
* converts a Node into ascii string and append it to 'str'
|
||||
@ -1796,9 +1818,15 @@ _outNode(StringInfo str, void *obj)
|
||||
case T_ConstraintTest:
|
||||
_outConstraintTest(str, obj);
|
||||
break;
|
||||
case T_ConstraintTestValue:
|
||||
_outConstraintTestValue(str, obj);
|
||||
break;
|
||||
case T_FuncCall:
|
||||
_outFuncCall(str, obj);
|
||||
break;
|
||||
case T_DomainConstraintValue:
|
||||
_outDomainConstraintValue(str, obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(WARNING, "_outNode: don't know how to print type %d ",
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.136 2002/11/06 00:00:44 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.137 2002/11/15 02:50:07 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Most of the read functions for plan nodes are tested. (In fact, they
|
||||
@ -949,12 +949,56 @@ _readConstraintTest(void)
|
||||
token = pg_strtok(&length); /* now read it */
|
||||
local_node->name = nullable_string(token, length);
|
||||
|
||||
token = pg_strtok(&length); /* get :domname */
|
||||
token = pg_strtok(&length); /* get domname */
|
||||
local_node->domname = nullable_string(token, length);
|
||||
|
||||
token = pg_strtok(&length); /* eat :check_expr */
|
||||
local_node->check_expr = nodeRead(true); /* now read it */
|
||||
|
||||
return local_node;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* _readConstraintTestValue
|
||||
*
|
||||
* ConstraintTestValue is a subclass of Node
|
||||
* ----------------
|
||||
*/
|
||||
static ConstraintTestValue *
|
||||
_readConstraintTestValue(void)
|
||||
{
|
||||
ConstraintTestValue *local_node;
|
||||
char *token;
|
||||
int length;
|
||||
|
||||
local_node = makeNode(ConstraintTestValue);
|
||||
token = pg_strtok(&length); /* eat :typeid */
|
||||
token = pg_strtok(&length); /* get typeid */
|
||||
local_node->typeId = atooid(token);
|
||||
token = pg_strtok(&length); /* eat :typemod */
|
||||
token = pg_strtok(&length); /* get typemod */
|
||||
local_node->typeMod = atoi(token);
|
||||
|
||||
return local_node;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* _readDomainConstraintValue
|
||||
*
|
||||
* DomainConstraintValue is a subclass of Node
|
||||
* ----------------
|
||||
*/
|
||||
static DomainConstraintValue *
|
||||
_readDomainConstraintValue(void)
|
||||
{
|
||||
DomainConstraintValue *local_node;
|
||||
|
||||
local_node = makeNode(DomainConstraintValue);
|
||||
|
||||
return local_node;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* _readVar
|
||||
*
|
||||
@ -2300,6 +2344,10 @@ parsePlanString(void)
|
||||
return_value = _readBooleanTest();
|
||||
else if (length == 14 && strncmp(token, "CONSTRAINTTEST", length) == 0)
|
||||
return_value = _readConstraintTest();
|
||||
else if (length == 21 && strncmp(token, "DOMAINCONSTRAINTVALUE", length) == 0)
|
||||
return_value = _readDomainConstraintValue();
|
||||
else if (length == 19 && strncmp(token, "CONSTRAINTTESTVALUE", length) == 0)
|
||||
return_value = _readConstraintTestValue();
|
||||
else
|
||||
elog(ERROR, "badly formatted planstring \"%.10s\"...", token);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.110 2002/11/06 22:31:24 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.111 2002/11/15 02:50:07 momjian Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -1926,6 +1926,8 @@ expression_tree_walker(Node *node,
|
||||
if (walker(((ConstraintTest *) node)->arg, context))
|
||||
return true;
|
||||
return walker(((ConstraintTest *) node)->check_expr, context);
|
||||
case T_ConstraintTestValue:
|
||||
break;
|
||||
case T_SubLink:
|
||||
{
|
||||
SubLink *sublink = (SubLink *) node;
|
||||
@ -2310,6 +2312,15 @@ expression_tree_mutator(Node *node,
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_ConstraintTestValue:
|
||||
{
|
||||
ConstraintTestValue *ctest = (ConstraintTestValue *) node;
|
||||
ConstraintTestValue *newnode;
|
||||
|
||||
FLATCOPY(newnode, ctest, ConstraintTestValue);
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_SubLink:
|
||||
{
|
||||
/*
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.253 2002/10/21 22:06:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.254 2002/11/15 02:50:07 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -2401,7 +2401,7 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
|
||||
Oid expected_type_id,
|
||||
given_type_id;
|
||||
|
||||
expr = transformExpr(pstate, expr);
|
||||
expr = transformExpr(pstate, expr, NULL);
|
||||
|
||||
/* Cannot contain subselects or aggregates */
|
||||
if (contain_subplans(expr))
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.377 2002/11/13 00:44:08 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.378 2002/11/15 02:50:08 momjian Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -393,7 +393,7 @@ static void doNegateFloat(Value *v);
|
||||
UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
|
||||
UPDATE USAGE USER USING
|
||||
|
||||
VACUUM VALID VALIDATOR VALUES VARCHAR VARYING
|
||||
VACUUM VALID VALIDATOR VALUE VALUES VARCHAR VARYING
|
||||
VERBOSE VERSION VIEW VOLATILE
|
||||
|
||||
WHEN WHERE WITH WITHOUT WORK WRITE
|
||||
@ -6406,6 +6406,11 @@ c_expr: columnref { $$ = (Node *) $1; }
|
||||
n->subselect = $2;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| VALUE
|
||||
{
|
||||
DomainConstraintValue *n = makeNode(DomainConstraintValue);
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
@ -7315,6 +7320,7 @@ reserved_keyword:
|
||||
| UNIQUE
|
||||
| USER
|
||||
| USING
|
||||
| VALUE
|
||||
| WHEN
|
||||
| WHERE
|
||||
;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.130 2002/11/13 00:44:09 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.131 2002/11/15 02:50:08 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -314,6 +314,7 @@ static const ScanKeyword ScanKeywords[] = {
|
||||
{"vacuum", VACUUM},
|
||||
{"valid", VALID},
|
||||
{"validator", VALIDATOR},
|
||||
{"value", VALUE},
|
||||
{"values", VALUES},
|
||||
{"varchar", VARCHAR},
|
||||
{"varying", VARYING},
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.98 2002/09/18 21:35:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.99 2002/11/15 02:50:08 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -283,7 +283,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
|
||||
* transformJoinOnClause() does. Just invoke transformExpr() to fix
|
||||
* up the operators, and we're done.
|
||||
*/
|
||||
result = transformExpr(pstate, result);
|
||||
result = transformExpr(pstate, result, NULL);
|
||||
|
||||
result = coerce_to_boolean(result, "JOIN/USING");
|
||||
|
||||
@ -317,7 +317,7 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
|
||||
pstate->p_namespace = makeList2(j->larg, j->rarg);
|
||||
|
||||
/* This part is just like transformWhereClause() */
|
||||
result = transformExpr(pstate, j->quals);
|
||||
result = transformExpr(pstate, j->quals, NULL);
|
||||
|
||||
result = coerce_to_boolean(result, "JOIN/ON");
|
||||
|
||||
@ -478,7 +478,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
|
||||
save_namespace = pstate->p_namespace;
|
||||
pstate->p_namespace = NIL;
|
||||
|
||||
funcexpr = transformExpr(pstate, r->funccallnode);
|
||||
funcexpr = transformExpr(pstate, r->funccallnode, NULL);
|
||||
|
||||
pstate->p_namespace = save_namespace;
|
||||
|
||||
@ -961,7 +961,7 @@ transformWhereClause(ParseState *pstate, Node *clause)
|
||||
if (clause == NULL)
|
||||
return NULL;
|
||||
|
||||
qual = transformExpr(pstate, clause);
|
||||
qual = transformExpr(pstate, clause, NULL);
|
||||
|
||||
qual = coerce_to_boolean(qual, "WHERE");
|
||||
|
||||
@ -1104,7 +1104,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
|
||||
* willing to match a resjunk target here, though the above cases must
|
||||
* ignore resjunk targets.
|
||||
*/
|
||||
expr = transformExpr(pstate, node);
|
||||
expr = transformExpr(pstate, node, NULL);
|
||||
|
||||
foreach(tl, tlist)
|
||||
{
|
||||
|
@ -8,13 +8,18 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.85 2002/10/24 22:09:00 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.86 2002/11/15 02:50:09 momjian 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"
|
||||
@ -405,8 +410,14 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
|
||||
for (;;)
|
||||
{
|
||||
HeapTuple tup;
|
||||
HeapTuple conTup;
|
||||
Form_pg_type typTup;
|
||||
|
||||
ScanKeyData key[1];
|
||||
int nkeys = 0;
|
||||
SysScanDesc scan;
|
||||
Relation conRel;
|
||||
|
||||
tup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(typeId),
|
||||
0, 0, 0);
|
||||
@ -419,7 +430,45 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
|
||||
if (typTup->typnotnull && notNull == NULL)
|
||||
notNull = pstrdup(NameStr(typTup->typname));
|
||||
|
||||
/* TODO: Add CHECK Constraints to domains */
|
||||
/* 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 = arg;
|
||||
r->testtype = CONSTR_TEST_CHECK;
|
||||
r->name = NameStr(c->conname);
|
||||
r->domname = NameStr(typTup->typname);
|
||||
r->check_expr = stringToNode(MemoryContextStrdup(CacheMemoryContext,
|
||||
DatumGetCString(DirectFunctionCall1(textout,
|
||||
val))));
|
||||
|
||||
arg = (Node *) r;
|
||||
}
|
||||
|
||||
systable_endscan(scan);
|
||||
heap_close(conRel, RowShareLock);
|
||||
|
||||
if (typTup->typtype != 'd')
|
||||
{
|
||||
@ -452,7 +501,8 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
|
||||
|
||||
r->arg = arg;
|
||||
r->testtype = CONSTR_TEST_NOTNULL;
|
||||
r->name = notNull;
|
||||
r->name = "NOT NULL";
|
||||
r->domname = notNull;
|
||||
r->check_expr = NULL;
|
||||
|
||||
arg = (Node *) r;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.129 2002/09/18 21:35:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.130 2002/11/15 02:50:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -20,6 +20,7 @@
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "nodes/params.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "parser/analyze.h"
|
||||
#include "parser/gramparse.h"
|
||||
#include "parser/parse.h"
|
||||
@ -83,7 +84,7 @@ parse_expr_init(void)
|
||||
* input and output of transformExpr; see SubLink for example.
|
||||
*/
|
||||
Node *
|
||||
transformExpr(ParseState *pstate, Node *expr)
|
||||
transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
{
|
||||
Node *result = NULL;
|
||||
|
||||
@ -152,7 +153,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
ExprFieldSelect *efs = (ExprFieldSelect *) expr;
|
||||
List *fields;
|
||||
|
||||
result = transformExpr(pstate, efs->arg);
|
||||
result = transformExpr(pstate, efs->arg, domVal);
|
||||
/* handle qualification, if any */
|
||||
foreach(fields, efs->fields)
|
||||
{
|
||||
@ -169,7 +170,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
case T_TypeCast:
|
||||
{
|
||||
TypeCast *tc = (TypeCast *) expr;
|
||||
Node *arg = transformExpr(pstate, tc->arg);
|
||||
Node *arg = transformExpr(pstate, tc->arg, domVal);
|
||||
|
||||
result = typecast_expression(arg, tc->typename);
|
||||
break;
|
||||
@ -204,14 +205,14 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
n->arg = a->lexpr;
|
||||
|
||||
result = transformExpr(pstate,
|
||||
(Node *) n);
|
||||
(Node *) n, domVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr);
|
||||
a->lexpr, domVal);
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr);
|
||||
a->rexpr, domVal);
|
||||
|
||||
result = (Node *) make_op(a->name,
|
||||
lexpr,
|
||||
@ -222,9 +223,9 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
case AND:
|
||||
{
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr);
|
||||
a->lexpr, domVal);
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr);
|
||||
a->rexpr, domVal);
|
||||
Expr *expr = makeNode(Expr);
|
||||
|
||||
lexpr = coerce_to_boolean(lexpr, "AND");
|
||||
@ -239,9 +240,9 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
case OR:
|
||||
{
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr);
|
||||
a->lexpr, domVal);
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr);
|
||||
a->rexpr, domVal);
|
||||
Expr *expr = makeNode(Expr);
|
||||
|
||||
lexpr = coerce_to_boolean(lexpr, "OR");
|
||||
@ -256,7 +257,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
case NOT:
|
||||
{
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr);
|
||||
a->rexpr, domVal);
|
||||
Expr *expr = makeNode(Expr);
|
||||
|
||||
rexpr = coerce_to_boolean(rexpr, "NOT");
|
||||
@ -270,9 +271,9 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
case DISTINCT:
|
||||
{
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr);
|
||||
a->lexpr, domVal);
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr);
|
||||
a->rexpr, domVal);
|
||||
|
||||
result = (Node *) make_op(a->name,
|
||||
lexpr,
|
||||
@ -293,7 +294,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
* Will result in a boolean constant node.
|
||||
*/
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr);
|
||||
a->lexpr, domVal);
|
||||
|
||||
ltype = exprType(lexpr);
|
||||
foreach(telem, (List *) a->rexpr)
|
||||
@ -317,7 +318,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
n->val.val.str = (matched ? "t" : "f");
|
||||
n->typename = SystemTypeName("bool");
|
||||
|
||||
result = transformExpr(pstate, (Node *) n);
|
||||
result = transformExpr(pstate, (Node *) n, domVal);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -331,7 +332,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
/* transform the list of arguments */
|
||||
foreach(args, fn->args)
|
||||
lfirst(args) = transformExpr(pstate,
|
||||
(Node *) lfirst(args));
|
||||
(Node *) lfirst(args), domVal);
|
||||
result = ParseFuncOrColumn(pstate,
|
||||
fn->funcname,
|
||||
fn->args,
|
||||
@ -405,7 +406,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
List *elist;
|
||||
|
||||
foreach(elist, left_list)
|
||||
lfirst(elist) = transformExpr(pstate, lfirst(elist));
|
||||
lfirst(elist) = transformExpr(pstate, lfirst(elist), domVal);
|
||||
|
||||
Assert(IsA(sublink->oper, A_Expr));
|
||||
op = ((A_Expr *) sublink->oper)->name;
|
||||
@ -504,7 +505,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
warg = (Node *) makeSimpleA_Expr(OP, "=",
|
||||
c->arg, warg);
|
||||
}
|
||||
neww->expr = transformExpr(pstate, warg);
|
||||
neww->expr = transformExpr(pstate, warg, domVal);
|
||||
|
||||
neww->expr = coerce_to_boolean(neww->expr, "CASE/WHEN");
|
||||
|
||||
@ -520,7 +521,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
n->val.type = T_Null;
|
||||
warg = (Node *) n;
|
||||
}
|
||||
neww->result = transformExpr(pstate, warg);
|
||||
neww->result = transformExpr(pstate, warg, domVal);
|
||||
|
||||
newargs = lappend(newargs, neww);
|
||||
typeids = lappendi(typeids, exprType(neww->result));
|
||||
@ -544,7 +545,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
n->val.type = T_Null;
|
||||
defresult = (Node *) n;
|
||||
}
|
||||
newc->defresult = transformExpr(pstate, defresult);
|
||||
newc->defresult = transformExpr(pstate, defresult, domVal);
|
||||
|
||||
/*
|
||||
* Note: default result is considered the most significant
|
||||
@ -580,7 +581,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
{
|
||||
NullTest *n = (NullTest *) expr;
|
||||
|
||||
n->arg = transformExpr(pstate, n->arg);
|
||||
n->arg = transformExpr(pstate, n->arg, domVal);
|
||||
/* the argument can be any type, so don't coerce it */
|
||||
result = expr;
|
||||
break;
|
||||
@ -617,7 +618,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
clausename = NULL; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
b->arg = transformExpr(pstate, b->arg);
|
||||
b->arg = transformExpr(pstate, b->arg, domVal);
|
||||
|
||||
b->arg = coerce_to_boolean(b->arg, clausename);
|
||||
|
||||
@ -625,6 +626,13 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
break;
|
||||
}
|
||||
|
||||
case T_DomainConstraintValue:
|
||||
{
|
||||
result = (Node *) copyObject(domVal);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* Quietly accept node types that may be presented when we are
|
||||
* called on an already-transformed tree.
|
||||
@ -936,6 +944,9 @@ exprType(Node *expr)
|
||||
case T_ConstraintTest:
|
||||
type = exprType(((ConstraintTest *) expr)->arg);
|
||||
break;
|
||||
case T_ConstraintTestValue:
|
||||
type = ((ConstraintTestValue *) expr)->typeId;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "exprType: Do not know how to get type for %d node",
|
||||
nodeTag(expr));
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.72 2002/11/13 00:39:47 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.73 2002/11/15 02:50:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -277,7 +277,7 @@ transformArraySubscripts(ParseState *pstate,
|
||||
{
|
||||
if (ai->lidx)
|
||||
{
|
||||
subexpr = transformExpr(pstate, ai->lidx);
|
||||
subexpr = transformExpr(pstate, ai->lidx, NULL);
|
||||
/* If it's not int4 already, try to coerce */
|
||||
subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
|
||||
INT4OID, -1,
|
||||
@ -299,7 +299,7 @@ transformArraySubscripts(ParseState *pstate,
|
||||
}
|
||||
lowerIndexpr = lappend(lowerIndexpr, subexpr);
|
||||
}
|
||||
subexpr = transformExpr(pstate, ai->uidx);
|
||||
subexpr = transformExpr(pstate, ai->uidx, NULL);
|
||||
/* If it's not int4 already, try to coerce */
|
||||
subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
|
||||
INT4OID, -1,
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.91 2002/09/28 20:00:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.92 2002/11/15 02:50:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -56,7 +56,7 @@ transformTargetEntry(ParseState *pstate,
|
||||
|
||||
/* Transform the node if caller didn't do it already */
|
||||
if (expr == NULL)
|
||||
expr = transformExpr(pstate, node);
|
||||
expr = transformExpr(pstate, node, NULL);
|
||||
|
||||
if (IsA(expr, RangeVar))
|
||||
elog(ERROR, "You can't use relation names alone in the target list, try relation.*.");
|
||||
|
@ -3,7 +3,7 @@
|
||||
* back to source text
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.124 2002/09/19 23:40:56 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.125 2002/11/15 02:50:09 momjian Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@ -2226,6 +2226,12 @@ get_rule_expr(Node *node, deparse_context *context,
|
||||
}
|
||||
break;
|
||||
|
||||
case T_ConstraintTestValue:
|
||||
{
|
||||
appendStringInfo(buf, "VALUE");
|
||||
}
|
||||
break;
|
||||
|
||||
case T_SubLink:
|
||||
get_sublink_expr(node, context);
|
||||
break;
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: indexing.h,v 1.76 2002/10/18 20:33:57 tgl Exp $
|
||||
* $Id: indexing.h,v 1.77 2002/11/15 02:50:10 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -40,6 +40,7 @@
|
||||
#define ConstraintNameNspIndex "pg_constraint_conname_nsp_index"
|
||||
#define ConstraintOidIndex "pg_constraint_oid_index"
|
||||
#define ConstraintRelidIndex "pg_constraint_conrelid_index"
|
||||
#define ConstraintTypidIndex "pg_constraint_contypid_index"
|
||||
#define ConversionDefaultIndex "pg_conversion_default_index"
|
||||
#define ConversionNameNspIndex "pg_conversion_name_nsp_index"
|
||||
#define ConversionOidIndex "pg_conversion_oid_index"
|
||||
@ -129,6 +130,8 @@ DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index on pg_class using btree(relname
|
||||
DECLARE_INDEX(pg_constraint_conname_nsp_index on pg_constraint using btree(conname name_ops, connamespace oid_ops));
|
||||
/* This following index is not used for a cache and is not unique */
|
||||
DECLARE_INDEX(pg_constraint_conrelid_index on pg_constraint using btree(conrelid oid_ops));
|
||||
/* This following index is not used for a cache and is not unique */
|
||||
DECLARE_INDEX(pg_constraint_contypid_index on pg_constraint using btree(contypid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_constraint_oid_index on pg_constraint using btree(oid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_conversion_default_index on pg_conversion using btree(connamespace oid_ops, conforencoding int4_ops, contoencoding int4_ops, oid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_conversion_name_nsp_index on pg_conversion using btree(conname name_ops, connamespace oid_ops));
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_constraint.h,v 1.4 2002/09/22 00:37:09 tgl Exp $
|
||||
* $Id: pg_constraint.h,v 1.5 2002/11/15 02:50:10 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
@ -140,6 +140,15 @@ typedef FormData_pg_constraint *Form_pg_constraint;
|
||||
* the FKCONSTR_MATCH_xxx constants defined in parsenodes.h.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Used for constraint support functions where the
|
||||
* and conrelid, contypid columns being looked up
|
||||
*/
|
||||
typedef enum CONSTRAINTCATEGORY {
|
||||
CONSTRAINT_RELATION,
|
||||
CONSTRAINT_DOMAIN,
|
||||
CONSTRAINT_ASSERTION
|
||||
} CONSTRAINTCATEGORY;
|
||||
|
||||
/*
|
||||
* prototypes for functions in pg_constraint.c
|
||||
@ -166,10 +175,10 @@ extern Oid CreateConstraintEntry(const char *constraintName,
|
||||
|
||||
extern void RemoveConstraintById(Oid conId);
|
||||
|
||||
extern bool ConstraintNameIsUsed(Oid relId, Oid relNamespace,
|
||||
const char *cname);
|
||||
extern char *GenerateConstraintName(Oid relId, Oid relNamespace,
|
||||
int *counter);
|
||||
extern bool ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace,
|
||||
const char *cname);
|
||||
extern char *GenerateConstraintName(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace,
|
||||
int *counter);
|
||||
extern bool ConstraintNameIsGenerated(const char *cname);
|
||||
|
||||
#endif /* PG_CONSTRAINT_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.77 2002/11/06 22:31:24 tgl Exp $
|
||||
* $Id: execnodes.h,v 1.78 2002/11/15 02:50:10 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -113,6 +113,13 @@ typedef struct ExprContext
|
||||
Datum *ecxt_aggvalues; /* precomputed values for Aggref nodes */
|
||||
bool *ecxt_aggnulls; /* null flags for Aggref nodes */
|
||||
|
||||
/*
|
||||
* Carry the domain value through the executor for application
|
||||
* in a domain constraint
|
||||
*/
|
||||
Datum domainValue_datum;
|
||||
bool domainValue_isNull;
|
||||
|
||||
/* Functions to call back when ExprContext is shut down */
|
||||
ExprContext_CB *ecxt_callbacks;
|
||||
} ExprContext;
|
||||
|
@ -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.122 2002/11/10 02:17:25 momjian Exp $
|
||||
* $Id: nodes.h,v 1.123 2002/11/15 02:50:10 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -171,6 +171,7 @@ typedef enum NodeTag
|
||||
T_ViewStmt,
|
||||
T_LoadStmt,
|
||||
T_CreateDomainStmt,
|
||||
T_DomainConstraintValue,
|
||||
T_CreatedbStmt,
|
||||
T_DropdbStmt,
|
||||
T_VacuumStmt,
|
||||
@ -231,6 +232,7 @@ typedef enum NodeTag
|
||||
T_NullTest,
|
||||
T_BooleanTest,
|
||||
T_ConstraintTest,
|
||||
T_ConstraintTestValue,
|
||||
T_CaseExpr,
|
||||
T_CaseWhen,
|
||||
T_FkConstraint,
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: parsenodes.h,v 1.213 2002/11/13 00:44:09 momjian Exp $
|
||||
* $Id: parsenodes.h,v 1.214 2002/11/15 02:50:12 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -285,9 +285,26 @@ typedef struct ConstraintTest
|
||||
Node *arg; /* input expression */
|
||||
ConstraintTestType testtype; /* test type */
|
||||
char *name; /* name of constraint (for error msgs) */
|
||||
char *domname; /* name of domain (for error messages) */
|
||||
Node *check_expr; /* for CHECK test, a boolean expression */
|
||||
} ConstraintTest;
|
||||
|
||||
/*
|
||||
* Placeholder node for the value to be processed by a domains
|
||||
* check constraint.
|
||||
*/
|
||||
typedef struct DomainConstraintValue
|
||||
{
|
||||
NodeTag type;
|
||||
} DomainConstraintValue;
|
||||
|
||||
typedef struct ConstraintTestValue
|
||||
{
|
||||
NodeTag type;
|
||||
Oid typeId;
|
||||
int32 typeMod;
|
||||
} ConstraintTestValue;
|
||||
|
||||
/*
|
||||
* ColumnDef - column definition (used in various creates)
|
||||
*
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: var.h,v 1.21 2002/06/20 20:29:51 momjian Exp $
|
||||
* $Id: var.h,v 1.22 2002/11/15 02:50:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -22,6 +22,7 @@ extern bool contain_var_reference(Node *node, int varno, int varattno,
|
||||
int levelsup);
|
||||
extern bool contain_whole_tuple_var(Node *node, int varno, int levelsup);
|
||||
extern bool contain_var_clause(Node *node);
|
||||
extern bool contain_var_tuple_clause(Node *node);
|
||||
extern List *pull_var_clause(Node *node, bool includeUpperVars);
|
||||
extern Node *flatten_join_alias_vars(Node *node, List *rtable, bool force);
|
||||
|
||||
|
@ -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_expr.h,v 1.28 2002/06/20 20:29:51 momjian Exp $
|
||||
* $Id: parse_expr.h,v 1.29 2002/11/15 02:50:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -21,7 +21,8 @@
|
||||
extern int max_expr_depth;
|
||||
extern bool Transform_null_equals;
|
||||
|
||||
extern Node *transformExpr(ParseState *pstate, Node *expr);
|
||||
|
||||
extern Node *transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal);
|
||||
extern Oid exprType(Node *expr);
|
||||
extern int32 exprTypmod(Node *expr);
|
||||
extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
|
||||
|
@ -103,35 +103,43 @@ drop domain domainint4arr restrict;
|
||||
drop domain domaintextarr restrict;
|
||||
create domain dnotnull varchar(15) NOT NULL;
|
||||
create domain dnull varchar(15);
|
||||
create domain dcheck varchar(15) NOT NULL CHECK (VALUE = 'a' OR VALUE = 'c' OR VALUE = 'd');
|
||||
create table nulltest
|
||||
( col1 dnotnull
|
||||
, col2 dnotnull NULL -- NOT NULL in the domain cannot be overridden
|
||||
, col3 dnull NOT NULL
|
||||
, col4 dnull
|
||||
, col5 dcheck CHECK (col5 IN ('c', 'd'))
|
||||
);
|
||||
INSERT INTO nulltest DEFAULT VALUES;
|
||||
ERROR: Domain dnotnull does not allow NULL values
|
||||
INSERT INTO nulltest values ('a', 'b', 'c', 'd'); -- Good
|
||||
INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
|
||||
INSERT INTO nulltest values ('a', 'b', 'c', 'd', 'c'); -- Good
|
||||
insert into nulltest values ('a', 'b', 'c', 'd', NULL);
|
||||
ERROR: Domain $1 constraint dcheck failed
|
||||
insert into nulltest values ('a', 'b', 'c', 'd', 'a');
|
||||
ERROR: ExecInsert: rejected due to CHECK constraint "nulltest_col5" on "nulltest"
|
||||
INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd');
|
||||
ERROR: Domain dnotnull does not allow NULL values
|
||||
INSERT INTO nulltest values ('a', NULL, 'c', 'd');
|
||||
INSERT INTO nulltest values ('a', NULL, 'c', 'd', 'c');
|
||||
ERROR: Domain dnotnull does not allow NULL values
|
||||
INSERT INTO nulltest values ('a', 'b', NULL, 'd');
|
||||
INSERT INTO nulltest values ('a', 'b', NULL, 'd', 'c');
|
||||
ERROR: ExecInsert: Fail to add null value in not null attribute col3
|
||||
INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
|
||||
INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
|
||||
-- Test copy
|
||||
COPY nulltest FROM stdin; --fail
|
||||
ERROR: copy: line 1, CopyFrom: Fail to add null value in not null attribute col3
|
||||
ERROR: copy: line 1, Domain $1 constraint dcheck failed
|
||||
lost synchronization with server, resetting connection
|
||||
SET autocommit TO 'on';
|
||||
-- Last row is bad
|
||||
COPY nulltest FROM stdin;
|
||||
ERROR: copy: line 3, CopyFrom: rejected due to CHECK constraint "nulltest_col5" on "nulltest"
|
||||
lost synchronization with server, resetting connection
|
||||
select * from nulltest;
|
||||
col1 | col2 | col3 | col4
|
||||
------+------+------+------
|
||||
a | b | c | d
|
||||
a | b | c |
|
||||
a | b | c |
|
||||
(3 rows)
|
||||
col1 | col2 | col3 | col4 | col5
|
||||
------+------+------+------+------
|
||||
a | b | c | d | c
|
||||
a | b | c | | d
|
||||
(2 rows)
|
||||
|
||||
-- Test out coerced (casted) constraints
|
||||
SELECT cast('1' as dnotnull);
|
||||
|
@ -83,29 +83,36 @@ drop domain domaintextarr restrict;
|
||||
|
||||
create domain dnotnull varchar(15) NOT NULL;
|
||||
create domain dnull varchar(15);
|
||||
create domain dcheck varchar(15) NOT NULL CHECK (VALUE = 'a' OR VALUE = 'c' OR VALUE = 'd');
|
||||
|
||||
create table nulltest
|
||||
( col1 dnotnull
|
||||
, col2 dnotnull NULL -- NOT NULL in the domain cannot be overridden
|
||||
, col3 dnull NOT NULL
|
||||
, col4 dnull
|
||||
, col5 dcheck CHECK (col5 IN ('c', 'd'))
|
||||
);
|
||||
INSERT INTO nulltest DEFAULT VALUES;
|
||||
INSERT INTO nulltest values ('a', 'b', 'c', 'd'); -- Good
|
||||
INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
|
||||
INSERT INTO nulltest values ('a', NULL, 'c', 'd');
|
||||
INSERT INTO nulltest values ('a', 'b', NULL, 'd');
|
||||
INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
|
||||
INSERT INTO nulltest values ('a', 'b', 'c', 'd', 'c'); -- Good
|
||||
insert into nulltest values ('a', 'b', 'c', 'd', NULL);
|
||||
insert into nulltest values ('a', 'b', 'c', 'd', 'a');
|
||||
INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd');
|
||||
INSERT INTO nulltest values ('a', NULL, 'c', 'd', 'c');
|
||||
INSERT INTO nulltest values ('a', 'b', NULL, 'd', 'c');
|
||||
INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
|
||||
|
||||
-- Test copy
|
||||
COPY nulltest FROM stdin; --fail
|
||||
a b \N d
|
||||
a b \N d \N
|
||||
\.
|
||||
|
||||
SET autocommit TO 'on';
|
||||
|
||||
-- Last row is bad
|
||||
COPY nulltest FROM stdin;
|
||||
a b c \N
|
||||
a b c \N c
|
||||
a b c \N d
|
||||
a b c \N a
|
||||
\.
|
||||
|
||||
select * from nulltest;
|
||||
|
Loading…
Reference in New Issue
Block a user