mirror of
https://github.com/postgres/postgres.git
synced 2025-07-07 00:36:50 +03:00
Add DOMAIN check constraints.
Rod Taylor
This commit is contained in:
@ -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.
|
||||
|
Reference in New Issue
Block a user