mirror of
https://github.com/postgres/postgres.git
synced 2025-07-15 19:21:59 +03:00
Preliminary code review for domain CHECK constraints patch: add documentation,
make VALUE a non-reserved word again, use less invasive method of passing ConstraintTestValue into transformExpr, fix problems with nested constraint testing, do correct thing with NULL result from a constraint expression, remove memory leak. Domain checks still need much more work if we are going to allow ALTER DOMAIN, however.
This commit is contained in:
@ -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.255 2002/12/12 15:49:33 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.256 2002/12/12 20:35:12 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -2401,7 +2401,7 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
|
||||
Oid expected_type_id,
|
||||
given_type_id;
|
||||
|
||||
expr = transformExpr(pstate, expr, NULL);
|
||||
expr = transformExpr(pstate, expr);
|
||||
|
||||
/* Cannot contain subselects or aggregates */
|
||||
if (contain_subplans(expr))
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.387 2002/12/12 15:49:36 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.388 2002/12/12 20:35:13 tgl 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 VALUE VALUES VARCHAR VARYING
|
||||
VACUUM VALID VALIDATOR VALUES VARCHAR VARYING
|
||||
VERBOSE VERSION VIEW VOLATILE
|
||||
|
||||
WHEN WHERE WITH WITHOUT WORK WRITE
|
||||
@ -6464,11 +6464,6 @@ c_expr: columnref { $$ = (Node *) $1; }
|
||||
n->subselect = $2;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| VALUE
|
||||
{
|
||||
DomainConstraintValue *n = makeNode(DomainConstraintValue);
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
@ -7378,7 +7373,6 @@ reserved_keyword:
|
||||
| UNIQUE
|
||||
| USER
|
||||
| USING
|
||||
| VALUE
|
||||
| WHEN
|
||||
| WHERE
|
||||
;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.131 2002/11/15 02:50:08 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.132 2002/12/12 20:35:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -314,7 +314,6 @@ 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.101 2002/12/12 15:49:38 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.102 2002/12/12 20:35:13 tgl 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, NULL);
|
||||
result = transformExpr(pstate, result);
|
||||
|
||||
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, NULL);
|
||||
result = transformExpr(pstate, j->quals);
|
||||
|
||||
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, NULL);
|
||||
funcexpr = transformExpr(pstate, r->funccallnode);
|
||||
|
||||
pstate->p_namespace = save_namespace;
|
||||
|
||||
@ -950,7 +950,7 @@ transformWhereClause(ParseState *pstate, Node *clause)
|
||||
if (clause == NULL)
|
||||
return NULL;
|
||||
|
||||
qual = transformExpr(pstate, clause, NULL);
|
||||
qual = transformExpr(pstate, clause);
|
||||
|
||||
qual = coerce_to_boolean(qual, "WHERE");
|
||||
|
||||
@ -1093,7 +1093,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, NULL);
|
||||
expr = transformExpr(pstate, node);
|
||||
|
||||
foreach(tl, tlist)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.90 2002/12/12 15:49:38 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.91 2002/12/12 20:35:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -458,9 +458,8 @@ coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
|
||||
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))));
|
||||
r->check_expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
|
||||
val)));
|
||||
|
||||
arg = (Node *) r;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.136 2002/12/12 15:49:39 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.137 2002/12/12 20:35:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -20,7 +20,6 @@
|
||||
#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"
|
||||
@ -84,7 +83,7 @@ parse_expr_init(void)
|
||||
* input and output of transformExpr; see SubLink for example.
|
||||
*/
|
||||
Node *
|
||||
transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
transformExpr(ParseState *pstate, Node *expr)
|
||||
{
|
||||
Node *result = NULL;
|
||||
|
||||
@ -152,7 +151,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
ExprFieldSelect *efs = (ExprFieldSelect *) expr;
|
||||
List *fields;
|
||||
|
||||
result = transformExpr(pstate, efs->arg, domVal);
|
||||
result = transformExpr(pstate, efs->arg);
|
||||
/* handle qualification, if any */
|
||||
foreach(fields, efs->fields)
|
||||
{
|
||||
@ -169,7 +168,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
case T_TypeCast:
|
||||
{
|
||||
TypeCast *tc = (TypeCast *) expr;
|
||||
Node *arg = transformExpr(pstate, tc->arg, domVal);
|
||||
Node *arg = transformExpr(pstate, tc->arg);
|
||||
|
||||
result = typecast_expression(arg, tc->typename);
|
||||
break;
|
||||
@ -204,14 +203,14 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
n->arg = (Expr *) a->lexpr;
|
||||
|
||||
result = transformExpr(pstate,
|
||||
(Node *) n, domVal);
|
||||
(Node *) n);
|
||||
}
|
||||
else
|
||||
{
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr, domVal);
|
||||
a->lexpr);
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr, domVal);
|
||||
a->rexpr);
|
||||
|
||||
result = (Node *) make_op(a->name,
|
||||
lexpr,
|
||||
@ -222,9 +221,9 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
case AND:
|
||||
{
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr, domVal);
|
||||
a->lexpr);
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr, domVal);
|
||||
a->rexpr);
|
||||
|
||||
lexpr = coerce_to_boolean(lexpr, "AND");
|
||||
rexpr = coerce_to_boolean(rexpr, "AND");
|
||||
@ -237,9 +236,9 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
case OR:
|
||||
{
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr, domVal);
|
||||
a->lexpr);
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr, domVal);
|
||||
a->rexpr);
|
||||
|
||||
lexpr = coerce_to_boolean(lexpr, "OR");
|
||||
rexpr = coerce_to_boolean(rexpr, "OR");
|
||||
@ -252,7 +251,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
case NOT:
|
||||
{
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr, domVal);
|
||||
a->rexpr);
|
||||
|
||||
rexpr = coerce_to_boolean(rexpr, "NOT");
|
||||
|
||||
@ -263,9 +262,9 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
case DISTINCT:
|
||||
{
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr, domVal);
|
||||
a->lexpr);
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr, domVal);
|
||||
a->rexpr);
|
||||
|
||||
result = (Node *) make_op(a->name,
|
||||
lexpr,
|
||||
@ -291,7 +290,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
* Will result in a boolean constant node.
|
||||
*/
|
||||
Node *lexpr = transformExpr(pstate,
|
||||
a->lexpr, domVal);
|
||||
a->lexpr);
|
||||
|
||||
ltype = exprType(lexpr);
|
||||
foreach(telem, (List *) a->rexpr)
|
||||
@ -315,7 +314,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
n->val.val.str = (matched ? "t" : "f");
|
||||
n->typename = SystemTypeName("bool");
|
||||
|
||||
result = transformExpr(pstate, (Node *) n, domVal);
|
||||
result = transformExpr(pstate, (Node *) n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -329,7 +328,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
/* transform the list of arguments */
|
||||
foreach(args, fn->args)
|
||||
lfirst(args) = transformExpr(pstate,
|
||||
(Node *) lfirst(args), domVal);
|
||||
(Node *) lfirst(args));
|
||||
result = ParseFuncOrColumn(pstate,
|
||||
fn->funcname,
|
||||
fn->args,
|
||||
@ -403,7 +402,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
List *elist;
|
||||
|
||||
foreach(elist, left_list)
|
||||
lfirst(elist) = transformExpr(pstate, lfirst(elist), domVal);
|
||||
lfirst(elist) = transformExpr(pstate, lfirst(elist));
|
||||
|
||||
Assert(IsA(sublink->oper, A_Expr));
|
||||
op = ((A_Expr *) sublink->oper)->name;
|
||||
@ -507,7 +506,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
(Node *) c->arg,
|
||||
warg);
|
||||
}
|
||||
neww->expr = (Expr *) transformExpr(pstate, warg, domVal);
|
||||
neww->expr = (Expr *) transformExpr(pstate, warg);
|
||||
|
||||
neww->expr = (Expr *) coerce_to_boolean((Node *) neww->expr,
|
||||
"CASE/WHEN");
|
||||
@ -524,7 +523,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
n->val.type = T_Null;
|
||||
warg = (Node *) n;
|
||||
}
|
||||
neww->result = (Expr *) transformExpr(pstate, warg, domVal);
|
||||
neww->result = (Expr *) transformExpr(pstate, warg);
|
||||
|
||||
newargs = lappend(newargs, neww);
|
||||
typeids = lappendi(typeids, exprType((Node *) neww->result));
|
||||
@ -548,7 +547,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
n->val.type = T_Null;
|
||||
defresult = (Node *) n;
|
||||
}
|
||||
newc->defresult = (Expr *) transformExpr(pstate, defresult, domVal);
|
||||
newc->defresult = (Expr *) transformExpr(pstate, defresult);
|
||||
|
||||
/*
|
||||
* Note: default result is considered the most significant
|
||||
@ -586,7 +585,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
{
|
||||
NullTest *n = (NullTest *) expr;
|
||||
|
||||
n->arg = (Expr *) transformExpr(pstate, (Node *) n->arg, domVal);
|
||||
n->arg = (Expr *) transformExpr(pstate, (Node *) n->arg);
|
||||
/* the argument can be any type, so don't coerce it */
|
||||
result = expr;
|
||||
break;
|
||||
@ -623,7 +622,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
clausename = NULL; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg, domVal);
|
||||
b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg);
|
||||
|
||||
b->arg = (Expr *) coerce_to_boolean((Node *) b->arg, clausename);
|
||||
|
||||
@ -631,21 +630,6 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
break;
|
||||
}
|
||||
|
||||
case T_DomainConstraintValue:
|
||||
{
|
||||
/*
|
||||
* If domVal is NULL, we are not translating an expression that
|
||||
* can use it
|
||||
*/
|
||||
if (domVal == NULL)
|
||||
elog(ERROR, "VALUE is not allowed in expression for node %d",
|
||||
nodeTag(expr));
|
||||
|
||||
result = (Node *) copyObject(domVal);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* Quietly accept node types that may be presented when we are
|
||||
* called on an already-transformed tree.
|
||||
@ -663,6 +647,7 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
||||
case T_FieldSelect:
|
||||
case T_RelabelType:
|
||||
case T_ConstraintTest:
|
||||
case T_ConstraintTestValue:
|
||||
{
|
||||
result = (Node *) expr;
|
||||
break;
|
||||
@ -700,6 +685,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
|
||||
int numnames = length(cref->fields);
|
||||
Node *node;
|
||||
RangeVar *rv;
|
||||
int levels_up;
|
||||
|
||||
/*----------
|
||||
* The allowed syntaxes are:
|
||||
@ -740,18 +726,30 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
|
||||
if (node == NULL)
|
||||
{
|
||||
/*
|
||||
* Not known as a column of any range-table entry, so
|
||||
* try to find the name as a relation ... but not if
|
||||
* Not known as a column of any range-table entry.
|
||||
*
|
||||
* Consider the possibility that it's VALUE in a domain
|
||||
* check expression. (We handle VALUE as a name, not a
|
||||
* keyword, to avoid breaking a lot of applications that
|
||||
* have used VALUE as a column name in the past.)
|
||||
*/
|
||||
if (pstate->p_value_substitute != NULL &&
|
||||
strcmp(name, "value") == 0)
|
||||
{
|
||||
node = (Node *) copyObject(pstate->p_value_substitute);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to find the name as a relation ... but not if
|
||||
* subscripts appear. Note also that only relations
|
||||
* already entered into the rangetable will be
|
||||
* recognized.
|
||||
*
|
||||
* This is a hack for backwards compatibility with
|
||||
* PostQUEL- inspired syntax. The preferred form now
|
||||
* PostQUEL-inspired syntax. The preferred form now
|
||||
* is "rel.*".
|
||||
*/
|
||||
int levels_up;
|
||||
|
||||
if (cref->indirection == NIL &&
|
||||
refnameRangeTblEntry(pstate, NULL, name,
|
||||
&levels_up) != NULL)
|
||||
@ -1055,7 +1053,8 @@ exprTypmod(Node *expr)
|
||||
break;
|
||||
case T_ConstraintTest:
|
||||
return exprTypmod((Node *) ((ConstraintTest *) expr)->arg);
|
||||
|
||||
case T_ConstraintTestValue:
|
||||
return ((ConstraintTestValue *) expr)->typeMod;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.75 2002/12/12 15:49:39 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.76 2002/12/12 20:35:13 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -272,7 +272,7 @@ transformArraySubscripts(ParseState *pstate,
|
||||
{
|
||||
if (ai->lidx)
|
||||
{
|
||||
subexpr = transformExpr(pstate, ai->lidx, NULL);
|
||||
subexpr = transformExpr(pstate, ai->lidx);
|
||||
/* If it's not int4 already, try to coerce */
|
||||
subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
|
||||
INT4OID, -1,
|
||||
@ -292,7 +292,7 @@ transformArraySubscripts(ParseState *pstate,
|
||||
}
|
||||
lowerIndexpr = lappend(lowerIndexpr, subexpr);
|
||||
}
|
||||
subexpr = transformExpr(pstate, ai->uidx, NULL);
|
||||
subexpr = transformExpr(pstate, ai->uidx);
|
||||
/* 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.93 2002/12/12 15:49:39 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.94 2002/12/12 20:35:13 tgl 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, NULL);
|
||||
expr = transformExpr(pstate, node);
|
||||
|
||||
if (IsA(expr, RangeVar))
|
||||
elog(ERROR, "You can't use relation names alone in the target list, try relation.*.");
|
||||
|
Reference in New Issue
Block a user