1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-15 19:21:59 +03:00

Add DOMAIN check constraints.

Rod Taylor
This commit is contained in:
Bruce Momjian
2002-11-15 02:50:21 +00:00
parent 2986aa6a66
commit 6b603e67dc
29 changed files with 641 additions and 147 deletions

View File

@ -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))

View File

@ -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
;

View File

@ -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},

View File

@ -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)
{

View File

@ -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;

View File

@ -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));

View File

@ -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,

View File

@ -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.*.");