mirror of
https://github.com/postgres/postgres.git
synced 2025-06-10 09:21:54 +03:00
Implement CASE expression.
This commit is contained in:
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.38 1998/11/27 19:52:00 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.39 1998/12/04 15:33:19 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -20,7 +20,7 @@
|
|||||||
* NOTES
|
* NOTES
|
||||||
* ExecEvalExpr() and ExecEvalVar() are hotspots. making these faster
|
* ExecEvalExpr() and ExecEvalVar() are hotspots. making these faster
|
||||||
* will speed up the entire system. Unfortunately they are currently
|
* will speed up the entire system. Unfortunately they are currently
|
||||||
* implemented recursively.. Eliminating the recursion is bound to
|
* implemented recursively. Eliminating the recursion is bound to
|
||||||
* improve the speed of the executor.
|
* improve the speed of the executor.
|
||||||
*
|
*
|
||||||
* ExecTargetList() is used to make tuple projections. Rather then
|
* ExecTargetList() is used to make tuple projections. Rather then
|
||||||
@ -205,7 +205,7 @@ ExecEvalAggreg(Aggreg *agg, ExprContext *econtext, bool *isNull)
|
|||||||
* variable with respect to given expression context.
|
* variable with respect to given expression context.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* As an entry condition, we expect that the the datatype the
|
* As an entry condition, we expect that the datatype the
|
||||||
* plan expects to get (as told by our "variable" argument) is in
|
* plan expects to get (as told by our "variable" argument) is in
|
||||||
* fact the datatype of the attribute the plan says to fetch (as
|
* fact the datatype of the attribute the plan says to fetch (as
|
||||||
* seen in the current context, identified by our "econtext"
|
* seen in the current context, identified by our "econtext"
|
||||||
@ -1124,6 +1124,79 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
|
|||||||
return const_value;
|
return const_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------
|
||||||
|
* ExecEvalCase
|
||||||
|
*
|
||||||
|
* Evaluate a CASE clause. Will have boolean expressions
|
||||||
|
* inside the WHEN clauses, and will have constants
|
||||||
|
* for results.
|
||||||
|
* - thomas 1998-11-09
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
static Datum
|
||||||
|
ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
|
||||||
|
{
|
||||||
|
List *clauses;
|
||||||
|
List *clause;
|
||||||
|
CaseWhen *wclause;
|
||||||
|
Datum const_value = 0;
|
||||||
|
bool isDone;
|
||||||
|
|
||||||
|
clauses = caseExpr->args;
|
||||||
|
|
||||||
|
/******************
|
||||||
|
* we evaluate each of the WHEN clauses in turn,
|
||||||
|
* as soon as one is true we return the corresponding
|
||||||
|
* result. If none are true then we return the value
|
||||||
|
* of the default clause, or NULL.
|
||||||
|
******************
|
||||||
|
*/
|
||||||
|
foreach(clause, clauses)
|
||||||
|
{
|
||||||
|
|
||||||
|
/******************
|
||||||
|
* We don't iterate over sets in the quals, so pass in an isDone
|
||||||
|
* flag, but ignore it.
|
||||||
|
******************
|
||||||
|
*/
|
||||||
|
|
||||||
|
wclause = lfirst(clause);
|
||||||
|
const_value = ExecEvalExpr((Node *) wclause->expr,
|
||||||
|
econtext,
|
||||||
|
isNull,
|
||||||
|
&isDone);
|
||||||
|
|
||||||
|
/******************
|
||||||
|
* if we have a true test, then we return the result,
|
||||||
|
* since the case statement is satisfied.
|
||||||
|
******************
|
||||||
|
*/
|
||||||
|
if (DatumGetInt32(const_value) != 0)
|
||||||
|
{
|
||||||
|
const_value = ExecEvalExpr((Node *) wclause->result,
|
||||||
|
econtext,
|
||||||
|
isNull,
|
||||||
|
&isDone);
|
||||||
|
return (Datum) const_value;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caseExpr->defresult)
|
||||||
|
{
|
||||||
|
const_value = ExecEvalExpr((Node *) caseExpr->defresult,
|
||||||
|
econtext,
|
||||||
|
isNull,
|
||||||
|
&isDone);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*isNull = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return const_value;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecEvalExpr
|
* ExecEvalExpr
|
||||||
*
|
*
|
||||||
@ -1236,13 +1309,18 @@ ExecEvalExpr(Node *expression,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case T_CaseExpr:
|
||||||
|
retDatum = (Datum) ExecEvalCase((CaseExpr *) expression, econtext, isNull);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "ExecEvalExpr: unknown expression type %d", nodeTag(expression));
|
elog(ERROR, "ExecEvalExpr: unknown expression type %d", nodeTag(expression));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retDatum;
|
return retDatum;
|
||||||
}
|
} /* ExecEvalExpr() */
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecQual / ExecTargetList
|
* ExecQual / ExecTargetList
|
||||||
@ -1642,3 +1720,4 @@ ExecProject(ProjectionInfo *projInfo, bool *isDone)
|
|||||||
InvalidBuffer, /* tuple has no buffer */
|
InvalidBuffer, /* tuple has no buffer */
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.50 1998/11/22 10:48:38 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.51 1998/12/04 15:33:33 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -943,6 +943,47 @@ _copySubLink(SubLink *from)
|
|||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* _copyCaseExpr
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
static CaseExpr *
|
||||||
|
_copyCaseExpr(CaseExpr *from)
|
||||||
|
{
|
||||||
|
CaseExpr *newnode = makeNode(CaseExpr);
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* copy remainder of node
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
newnode->casetype = from->casetype;
|
||||||
|
|
||||||
|
Node_Copy(from, newnode, arg);
|
||||||
|
Node_Copy(from, newnode, args);
|
||||||
|
Node_Copy(from, newnode, defresult);
|
||||||
|
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* _copyCaseWhen
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
static CaseWhen *
|
||||||
|
_copyCaseWhen(CaseWhen *from)
|
||||||
|
{
|
||||||
|
CaseWhen *newnode = makeNode(CaseWhen);
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* copy remainder of node
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
Node_Copy(from, newnode, expr);
|
||||||
|
Node_Copy(from, newnode, result);
|
||||||
|
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
static Array *
|
static Array *
|
||||||
_copyArray(Array *from)
|
_copyArray(Array *from)
|
||||||
{
|
{
|
||||||
@ -1734,6 +1775,12 @@ copyObject(void *from)
|
|||||||
case T_SubLink:
|
case T_SubLink:
|
||||||
retval = _copySubLink(from);
|
retval = _copySubLink(from);
|
||||||
break;
|
break;
|
||||||
|
case T_CaseExpr:
|
||||||
|
retval = _copyCaseExpr(from);
|
||||||
|
break;
|
||||||
|
case T_CaseWhen:
|
||||||
|
retval = _copyCaseWhen(from);
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RELATION NODES
|
* RELATION NODES
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.48 1998/11/22 10:48:39 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.49 1998/12/04 15:33:33 thomas Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Every (plan) node in POSTGRES has an associated "out" routine which
|
* Every (plan) node in POSTGRES has an associated "out" routine which
|
||||||
@ -1635,6 +1635,82 @@ _outAConst(StringInfo str, A_Const *node)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_outConstraint(StringInfo str, Constraint *node)
|
||||||
|
{
|
||||||
|
char buf[500];
|
||||||
|
|
||||||
|
sprintf(buf," %s :type",
|
||||||
|
((node->name != NULL)? node->name: "<>"));
|
||||||
|
appendStringInfo(str, buf);
|
||||||
|
|
||||||
|
switch (node->contype)
|
||||||
|
{
|
||||||
|
case CONSTR_PRIMARY:
|
||||||
|
sprintf(buf," PRIMARY KEY ");
|
||||||
|
appendStringInfo(str, buf);
|
||||||
|
_outNode(str, node->keys);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONSTR_CHECK:
|
||||||
|
sprintf(buf," CHECK ");
|
||||||
|
appendStringInfo(str, buf);
|
||||||
|
appendStringInfo(str, node->def);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONSTR_DEFAULT:
|
||||||
|
sprintf(buf," DEFAULT ");
|
||||||
|
appendStringInfo(str, buf);
|
||||||
|
appendStringInfo(str, node->def);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONSTR_NOTNULL:
|
||||||
|
sprintf(buf," NOT NULL ");
|
||||||
|
appendStringInfo(str, buf);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONSTR_UNIQUE:
|
||||||
|
sprintf(buf," UNIQUE ");
|
||||||
|
appendStringInfo(str, buf);
|
||||||
|
_outNode(str, node->keys);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
sprintf(buf,"<unrecognized constraint>");
|
||||||
|
appendStringInfo(str, buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_outCaseExpr(StringInfo str, CaseExpr *node)
|
||||||
|
{
|
||||||
|
char buf[500];
|
||||||
|
|
||||||
|
sprintf(buf, "CASE ");
|
||||||
|
appendStringInfo(str, buf);
|
||||||
|
_outNode(str, node->args);
|
||||||
|
sprintf(buf, " :default ");
|
||||||
|
appendStringInfo(str, buf);
|
||||||
|
_outNode(str, node->defresult);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_outCaseWhen(StringInfo str, CaseWhen *node)
|
||||||
|
{
|
||||||
|
char buf[500];
|
||||||
|
|
||||||
|
sprintf(buf, " :when ");
|
||||||
|
appendStringInfo(str, buf);
|
||||||
|
_outNode(str, node->expr);
|
||||||
|
sprintf(buf, " :then ");
|
||||||
|
appendStringInfo(str, buf);
|
||||||
|
_outNode(str, node->result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _outNode -
|
* _outNode -
|
||||||
* converts a Node into ascii string and append it to 'str'
|
* converts a Node into ascii string and append it to 'str'
|
||||||
@ -1861,6 +1937,15 @@ _outNode(StringInfo str, void *obj)
|
|||||||
case T_A_Const:
|
case T_A_Const:
|
||||||
_outAConst(str, obj);
|
_outAConst(str, obj);
|
||||||
break;
|
break;
|
||||||
|
case T_Constraint:
|
||||||
|
_outConstraint(str, obj);
|
||||||
|
break;
|
||||||
|
case T_CaseExpr:
|
||||||
|
_outCaseExpr(str, obj);
|
||||||
|
break;
|
||||||
|
case T_CaseWhen:
|
||||||
|
_outCaseWhen(str, obj);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
elog(NOTICE, "_outNode: don't know how to print type %d ",
|
elog(NOTICE, "_outNode: don't know how to print type %d ",
|
||||||
nodeTag(obj));
|
nodeTag(obj));
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.33 1998/11/22 10:48:43 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.34 1998/12/04 15:34:05 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -437,7 +437,7 @@ create_nestloop_node(JoinPath *best_path,
|
|||||||
* used in the inner scan path, so we need only consider the first
|
* used in the inner scan path, so we need only consider the first
|
||||||
* set of qualifications in indxqual.
|
* set of qualifications in indxqual.
|
||||||
*
|
*
|
||||||
* But there may be more than one clauses in this "first set" in the
|
* But there may be more than one clause in this "first set" in the
|
||||||
* case of multi-column indices. - vadim 03/18/97
|
* case of multi-column indices. - vadim 03/18/97
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -735,6 +735,11 @@ fix_indxqual_references(Node *clause, Path *index_path)
|
|||||||
else
|
else
|
||||||
return clause;
|
return clause;
|
||||||
}
|
}
|
||||||
|
else if (IsA(clause, CaseExpr))
|
||||||
|
{
|
||||||
|
elog(NOTICE,"optimizer: fix_indxqual_references sees CaseExpr");
|
||||||
|
return clause;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
List *oldclauses = (List *) clause;
|
List *oldclauses = (List *) clause;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.25 1998/11/27 19:52:07 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.26 1998/12/04 15:34:14 thomas Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -306,6 +306,26 @@ make_andclause(List *andclauses)
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CASE clause functions
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* case_clause--
|
||||||
|
*
|
||||||
|
* Returns t iff its argument is a 'case' clause: (CASE { expr }).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
case_clause(Node *clause)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(clause != NULL &&
|
||||||
|
nodeTag(clause) == T_CaseExpr);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* *
|
* *
|
||||||
* *
|
* *
|
||||||
@ -540,6 +560,19 @@ fix_opid(Node *clause)
|
|||||||
fix_opid((Node *) get_leftop((Expr *) lfirst(lst)));
|
fix_opid((Node *) get_leftop((Expr *) lfirst(lst)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (case_clause(clause))
|
||||||
|
{
|
||||||
|
List *lst;
|
||||||
|
|
||||||
|
fix_opid(((CaseExpr *) clause)->defresult);
|
||||||
|
|
||||||
|
/* Run through the WHEN clauses... */
|
||||||
|
foreach(lst, ((CaseExpr *) clause)->args)
|
||||||
|
{
|
||||||
|
fix_opid(((CaseWhen *) lfirst(lst))->expr);
|
||||||
|
fix_opid(((CaseWhen *) lfirst(lst))->result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,13 +610,12 @@ fix_opids(List *clauses)
|
|||||||
* returned for the value if it is unknown or null.
|
* returned for the value if it is unknown or null.
|
||||||
* END OF OLD OBSOLETE COMMENT.
|
* END OF OLD OBSOLETE COMMENT.
|
||||||
* NEW COMMENT:
|
* NEW COMMENT:
|
||||||
* when defining rules one of the attibutes of the operator can
|
* when defining rules one of the attributes of the operator can
|
||||||
* be a Param node (which is supposed to be treated as a constant).
|
* be a Param node (which is supposed to be treated as a constant).
|
||||||
* However as there is no value specified for a parameter until run time
|
* However as there is no value specified for a parameter until run time
|
||||||
* this routine used to return "" as value, which made 'compute_selec'
|
* this routine used to return "" as value, which caused 'compute_selec'
|
||||||
* to bomb (because it was expecting a lisp integer and got back a lisp
|
* to bomb (because it was expecting a lisp integer and got back a lisp
|
||||||
* string). Now the code returns a plain old good "lispInteger(0)".
|
* string). Now the code returns a plain old good "lispInteger(0)".
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
get_relattval(Node *clause,
|
get_relattval(Node *clause,
|
||||||
@ -787,3 +819,4 @@ CommuteClause(Node *clause)
|
|||||||
lfirst(((Expr *) clause)->args) = lsecond(((Expr *) clause)->args);
|
lfirst(((Expr *) clause)->args) = lsecond(((Expr *) clause)->args);
|
||||||
lsecond(((Expr *) clause)->args) = temp;
|
lsecond(((Expr *) clause)->args) = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.20 1998/09/22 21:48:27 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.21 1998/12/04 15:34:15 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -482,7 +482,6 @@ flatten_tlistentry(Node *tlistentry, List *flat_tlist)
|
|||||||
flatten_tlistentry(lfirst(elt), flat_tlist));
|
flatten_tlistentry(lfirst(elt), flat_tlist));
|
||||||
|
|
||||||
return ((Node *) make_funcclause((Func *) expr->oper, temp_result));
|
return ((Node *) make_funcclause((Func *) expr->oper, temp_result));
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (IsA(tlistentry, Aggreg))
|
else if (IsA(tlistentry, Aggreg))
|
||||||
{
|
{
|
||||||
@ -509,19 +508,36 @@ flatten_tlistentry(Node *tlistentry, List *flat_tlist)
|
|||||||
|
|
||||||
return tlistentry;
|
return tlistentry;
|
||||||
}
|
}
|
||||||
|
else if (case_clause(tlistentry))
|
||||||
|
{
|
||||||
|
CaseExpr *cexpr = (CaseExpr *) tlistentry;
|
||||||
|
CaseWhen *cwhen;
|
||||||
|
List *elt = NIL;
|
||||||
|
|
||||||
|
foreach(elt, cexpr->args)
|
||||||
|
cwhen = (CaseWhen *)lfirst(elt);
|
||||||
|
cwhen->result = flatten_tlistentry(cwhen->result, flat_tlist);
|
||||||
|
cexpr->defresult = flatten_tlistentry(cexpr->defresult, flat_tlist);
|
||||||
|
|
||||||
|
return ((Node *) cexpr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Expr *expr = (Expr *) tlistentry;
|
Expr *expr, *final;
|
||||||
|
Var *left, *right;
|
||||||
Var *left = (Var *) flatten_tlistentry((Node *) get_leftop(expr),
|
|
||||||
flat_tlist);
|
|
||||||
Var *right = (Var *) flatten_tlistentry((Node *) get_rightop(expr),
|
|
||||||
flat_tlist);
|
|
||||||
Expr *final = make_opclause((Oper *) expr->oper, left, right);
|
|
||||||
|
|
||||||
Assert(IsA(tlistentry, Expr));
|
Assert(IsA(tlistentry, Expr));
|
||||||
|
|
||||||
|
expr = (Expr *) tlistentry;
|
||||||
|
left = (Var *) flatten_tlistentry((Node *) get_leftop(expr),
|
||||||
|
flat_tlist);
|
||||||
|
right = (Var *) flatten_tlistentry((Node *) get_rightop(expr),
|
||||||
|
flat_tlist);
|
||||||
|
|
||||||
|
final = make_opclause((Oper *) expr->oper, left, right);
|
||||||
final->opType = expr->opType;
|
final->opType = expr->opType;
|
||||||
final->typeOid = expr->typeOid;
|
final->typeOid = expr->typeOid;
|
||||||
|
|
||||||
return (Node *)final;
|
return (Node *)final;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.13 1998/09/01 03:24:00 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.14 1998/12/04 15:34:15 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -137,6 +137,21 @@ contain_var_clause(Node *clause)
|
|||||||
else if (is_opclause(clause))
|
else if (is_opclause(clause))
|
||||||
return (contain_var_clause((Node *) get_leftop((Expr *) clause)) ||
|
return (contain_var_clause((Node *) get_leftop((Expr *) clause)) ||
|
||||||
contain_var_clause((Node *) get_rightop((Expr *) clause)));
|
contain_var_clause((Node *) get_rightop((Expr *) clause)));
|
||||||
|
else if (case_clause(clause))
|
||||||
|
{
|
||||||
|
List *args;
|
||||||
|
CaseWhen *when;
|
||||||
|
|
||||||
|
foreach(args, ((CaseExpr *) clause)->args)
|
||||||
|
{
|
||||||
|
when = lfirst(args);
|
||||||
|
if (contain_var_clause(when->expr))
|
||||||
|
return TRUE;
|
||||||
|
if (contain_var_clause(when->result))
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return (contain_var_clause(((CaseExpr *) clause)->defresult));
|
||||||
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -199,6 +214,18 @@ pull_var_clause(Node *clause)
|
|||||||
else if (is_opclause(clause))
|
else if (is_opclause(clause))
|
||||||
retval = nconc(pull_var_clause((Node *) get_leftop((Expr *) clause)),
|
retval = nconc(pull_var_clause((Node *) get_leftop((Expr *) clause)),
|
||||||
pull_var_clause((Node *) get_rightop((Expr *) clause)));
|
pull_var_clause((Node *) get_rightop((Expr *) clause)));
|
||||||
|
else if (case_clause(clause))
|
||||||
|
{
|
||||||
|
List *temp;
|
||||||
|
|
||||||
|
foreach(temp, ((CaseExpr *) clause)->args)
|
||||||
|
{
|
||||||
|
retval = nconc(retval, pull_var_clause(((CaseWhen *) lfirst(temp))->expr));
|
||||||
|
retval = nconc(retval, pull_var_clause(((CaseWhen *) lfirst(temp))->result));
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = nconc(retval, pull_var_clause(((CaseExpr *) clause)->defresult));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
retval = NIL;
|
retval = NIL;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.89 1998/10/28 16:06:54 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.90 1998/12/04 15:34:28 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -396,7 +396,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
|||||||
*/
|
*/
|
||||||
if ((qry->hasAggs == false) && (qry->havingQual != NULL))
|
if ((qry->hasAggs == false) && (qry->havingQual != NULL))
|
||||||
{
|
{
|
||||||
elog(ERROR, "This is not a valid having query!");
|
elog(ERROR, "SELECT/HAVING requires aggregates to be valid");
|
||||||
return (Query *) NIL;
|
return (Query *) NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,7 +621,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "parser: internal error; unrecognized constraint", NULL);
|
elog(ERROR, "parser: unrecognized constraint (internal error)", NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
clist = lnext(clist);
|
clist = lnext(clist);
|
||||||
@ -653,16 +653,16 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
|||||||
|
|
||||||
case CONSTR_NOTNULL:
|
case CONSTR_NOTNULL:
|
||||||
case CONSTR_DEFAULT:
|
case CONSTR_DEFAULT:
|
||||||
elog(ERROR, "parser: internal error; illegal context for constraint", NULL);
|
elog(ERROR, "parser: illegal context for constraint (internal error)", NULL);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "parser: internal error; unrecognized constraint", NULL);
|
elog(ERROR, "parser: unrecognized constraint (internal error)", NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "parser: internal error; unrecognized node", NULL);
|
elog(ERROR, "parser: unrecognized node (internal error)", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
elements = lnext(elements);
|
elements = lnext(elements);
|
||||||
@ -684,7 +684,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
|||||||
{
|
{
|
||||||
constraint = lfirst(dlist);
|
constraint = lfirst(dlist);
|
||||||
if (nodeTag(constraint) != T_Constraint)
|
if (nodeTag(constraint) != T_Constraint)
|
||||||
elog(ERROR, "parser: internal error; unrecognized deferred node", NULL);
|
elog(ERROR, "parser: unrecognized deferred node (internal error)", NULL);
|
||||||
|
|
||||||
if (constraint->contype == CONSTR_PRIMARY)
|
if (constraint->contype == CONSTR_PRIMARY)
|
||||||
{
|
{
|
||||||
@ -695,7 +695,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
|||||||
have_pkey = TRUE;
|
have_pkey = TRUE;
|
||||||
}
|
}
|
||||||
else if (constraint->contype != CONSTR_UNIQUE)
|
else if (constraint->contype != CONSTR_UNIQUE)
|
||||||
elog(ERROR, "parser: internal error; unrecognized deferred constraint", NULL);
|
elog(ERROR, "parser: unrecognized deferred constraint (internal error)", NULL);
|
||||||
|
|
||||||
index = makeNode(IndexStmt);
|
index = makeNode(IndexStmt);
|
||||||
|
|
||||||
@ -735,7 +735,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
|||||||
columns = lnext(columns);
|
columns = lnext(columns);
|
||||||
}
|
}
|
||||||
if (column == NULL)
|
if (column == NULL)
|
||||||
elog(ERROR, "parser: column '%s' in key does not exist", key->name);
|
elog(ERROR, "CREATE TABLE column '%s' in key does not exist", key->name);
|
||||||
|
|
||||||
if (constraint->contype == CONSTR_PRIMARY)
|
if (constraint->contype == CONSTR_PRIMARY)
|
||||||
column->is_not_null = TRUE;
|
column->is_not_null = TRUE;
|
||||||
@ -753,7 +753,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (index->idxname == NULL)
|
if (index->idxname == NULL)
|
||||||
elog(ERROR, "parser: unable to construct implicit index for table %s"
|
elog(ERROR, "CREATE TABLE unable to construct implicit index for table %s"
|
||||||
"; name too long", stmt->relname);
|
"; name too long", stmt->relname);
|
||||||
else
|
else
|
||||||
elog(NOTICE, "CREATE TABLE/%s will create implicit index %s for table %s",
|
elog(NOTICE, "CREATE TABLE/%s will create implicit index %s for table %s",
|
||||||
@ -918,8 +918,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
/*
|
/*
|
||||||
* The havingQual has a similar meaning as "qual" in the where
|
* The havingQual has a similar meaning as "qual" in the where
|
||||||
* statement. So we can easily use the code from the "where clause"
|
* statement. So we can easily use the code from the "where clause"
|
||||||
* with some additional traversals done in
|
* with some additional traversals done in optimizer/plan/planner.c
|
||||||
* .../optimizer/plan/planner.c
|
|
||||||
*/
|
*/
|
||||||
qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
|
qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
|
||||||
|
|
||||||
@ -955,7 +954,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
*/
|
*/
|
||||||
if ((qry->hasAggs == false) && (qry->havingQual != NULL))
|
if ((qry->hasAggs == false) && (qry->havingQual != NULL))
|
||||||
{
|
{
|
||||||
elog(ERROR, "This is not a valid having query!");
|
elog(ERROR, "SELECT/HAVING requires aggregates to be valid");
|
||||||
return (Query *) NIL;
|
return (Query *) NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.37 1998/10/14 15:56:43 thomas Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.38 1998/12/04 15:34:29 thomas Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -208,6 +208,8 @@ Oid param_type(int t); /* used in parse_expr.c */
|
|||||||
%type <list> row_descriptor, row_list, c_list, c_expr
|
%type <list> row_descriptor, row_list, c_list, c_expr
|
||||||
%type <node> row_expr
|
%type <node> row_expr
|
||||||
%type <str> row_op
|
%type <str> row_op
|
||||||
|
%type <node> case_expr, case_arg, when_clause, case_default
|
||||||
|
%type <list> when_clause_list
|
||||||
%type <ival> sub_type
|
%type <ival> sub_type
|
||||||
%type <list> OptCreateAs, CreateAsList
|
%type <list> OptCreateAs, CreateAsList
|
||||||
%type <node> CreateAsElement
|
%type <node> CreateAsElement
|
||||||
@ -259,26 +261,27 @@ Oid param_type(int t); /* used in parse_expr.c */
|
|||||||
/* Keywords (in SQL92 reserved words) */
|
/* Keywords (in SQL92 reserved words) */
|
||||||
%token ABSOLUTE, ACTION, ADD, ALL, ALTER, AND, ANY, AS, ASC,
|
%token ABSOLUTE, ACTION, ADD, ALL, ALTER, AND, ANY, AS, ASC,
|
||||||
BEGIN_TRANS, BETWEEN, BOTH, BY,
|
BEGIN_TRANS, BETWEEN, BOTH, BY,
|
||||||
CASCADE, CAST, CHAR, CHARACTER, CHECK, CLOSE, COLLATE, COLUMN, COMMIT,
|
CASCADE, CASE, CAST, CHAR, CHARACTER, CHECK, CLOSE,
|
||||||
|
COALESCE, COLLATE, COLUMN, COMMIT,
|
||||||
CONSTRAINT, CREATE, CROSS, CURRENT, CURRENT_DATE, CURRENT_TIME,
|
CONSTRAINT, CREATE, CROSS, CURRENT, CURRENT_DATE, CURRENT_TIME,
|
||||||
CURRENT_TIMESTAMP, CURRENT_USER, CURSOR,
|
CURRENT_TIMESTAMP, CURRENT_USER, CURSOR,
|
||||||
DAY_P, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP,
|
DAY_P, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP,
|
||||||
END_TRANS, EXECUTE, EXISTS, EXTRACT,
|
ELSE, END_TRANS, EXECUTE, EXISTS, EXTRACT,
|
||||||
FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
|
FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
|
||||||
GRANT, GROUP, HAVING, HOUR_P,
|
GRANT, GROUP, HAVING, HOUR_P,
|
||||||
IN, INNER_P, INSENSITIVE, INSERT, INTERVAL, INTO, IS,
|
IN, INNER_P, INSENSITIVE, INSERT, INTERVAL, INTO, IS,
|
||||||
JOIN, KEY, LANGUAGE, LEADING, LEFT, LIKE, LOCAL,
|
JOIN, KEY, LANGUAGE, LEADING, LEFT, LIKE, LOCAL,
|
||||||
MATCH, MINUTE_P, MONTH_P, NAMES,
|
MATCH, MINUTE_P, MONTH_P, NAMES,
|
||||||
NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULL_P, NUMERIC,
|
NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULLIF, NULL_P, NUMERIC,
|
||||||
OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P,
|
OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P,
|
||||||
PARTIAL, POSITION, PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE, PUBLIC,
|
PARTIAL, POSITION, PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE, PUBLIC,
|
||||||
READ, REFERENCES, RELATIVE, REVOKE, RIGHT, ROLLBACK,
|
READ, REFERENCES, RELATIVE, REVOKE, RIGHT, ROLLBACK,
|
||||||
SCROLL, SECOND_P, SELECT, SET, SUBSTRING,
|
SCROLL, SECOND_P, SELECT, SET, SUBSTRING,
|
||||||
TABLE, TIME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE,
|
TABLE, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE,
|
||||||
TO, TRAILING, TRANSACTION, TRIM, TRUE_P,
|
TO, TRAILING, TRANSACTION, TRIM, TRUE_P,
|
||||||
UNION, UNIQUE, UPDATE, USER, USING,
|
UNION, UNIQUE, UPDATE, USER, USING,
|
||||||
VALUES, VARCHAR, VARYING, VIEW,
|
VALUES, VARCHAR, VARYING, VIEW,
|
||||||
WHERE, WITH, WORK, YEAR_P, ZONE
|
WHEN, WHERE, WITH, WORK, YEAR_P, ZONE
|
||||||
|
|
||||||
/* Keywords (in SQL3 reserved words) */
|
/* Keywords (in SQL3 reserved words) */
|
||||||
%token TRIGGER
|
%token TRIGGER
|
||||||
@ -2861,7 +2864,7 @@ opt_array_bounds: '[' ']' nest_array_bounds
|
|||||||
{ $$ = lcons(makeInteger(-1), $3); }
|
{ $$ = lcons(makeInteger(-1), $3); }
|
||||||
| '[' Iconst ']' nest_array_bounds
|
| '[' Iconst ']' nest_array_bounds
|
||||||
{ $$ = lcons(makeInteger($2), $4); }
|
{ $$ = lcons(makeInteger($2), $4); }
|
||||||
| /* EMPTY */
|
| /*EMPTY*/
|
||||||
{ $$ = NIL; }
|
{ $$ = NIL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -3276,14 +3279,14 @@ sub_type: ANY { $$ = ANY_SUBLINK; }
|
|||||||
| ALL { $$ = ALL_SUBLINK; }
|
| ALL { $$ = ALL_SUBLINK; }
|
||||||
;
|
;
|
||||||
|
|
||||||
/*
|
/* General expressions
|
||||||
* This is the heart of the expression syntax.
|
* This is the heart of the expression syntax.
|
||||||
* Note that the BETWEEN clause looks similar to a boolean expression
|
* Note that the BETWEEN clause looks similar to a boolean expression
|
||||||
* and so we must define b_expr which is almost the same as a_expr
|
* and so we must define b_expr which is almost the same as a_expr
|
||||||
* but without the boolean expressions.
|
* but without the boolean expressions.
|
||||||
* All operations are allowed in a BETWEEN clause if surrounded by parens.
|
* All operations/expressions are allowed in a BETWEEN clause
|
||||||
|
* if surrounded by parens.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
a_expr: attr opt_indirection
|
a_expr: attr opt_indirection
|
||||||
{
|
{
|
||||||
$1->indirection = $2;
|
$1->indirection = $2;
|
||||||
@ -3895,14 +3898,15 @@ a_expr: attr opt_indirection
|
|||||||
{ $$ = makeA_Expr(OR, NULL, $1, $3); }
|
{ $$ = makeA_Expr(OR, NULL, $1, $3); }
|
||||||
| NOT a_expr
|
| NOT a_expr
|
||||||
{ $$ = makeA_Expr(NOT, NULL, NULL, $2); }
|
{ $$ = makeA_Expr(NOT, NULL, NULL, $2); }
|
||||||
|
| case_expr
|
||||||
|
{ $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
/*
|
/* Restricted expressions
|
||||||
* b_expr is a subset of the complete expression syntax
|
* b_expr is a subset of the complete expression syntax
|
||||||
* defined by a_expr. b_expr is used in BETWEEN clauses
|
* defined by a_expr. b_expr is used in BETWEEN clauses
|
||||||
* to eliminate parser ambiguities stemming from the AND keyword.
|
* to eliminate parser ambiguities stemming from the AND keyword.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
b_expr: attr opt_indirection
|
b_expr: attr opt_indirection
|
||||||
{
|
{
|
||||||
$1->indirection = $2;
|
$1->indirection = $2;
|
||||||
@ -4150,7 +4154,7 @@ opt_indirection: '[' a_expr ']' opt_indirection
|
|||||||
ai->uidx = $4;
|
ai->uidx = $4;
|
||||||
$$ = lcons(ai, $6);
|
$$ = lcons(ai, $6);
|
||||||
}
|
}
|
||||||
| /* EMPTY */
|
| /*EMPTY*/
|
||||||
{ $$ = NIL; }
|
{ $$ = NIL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -4169,7 +4173,7 @@ extract_list: extract_arg FROM a_expr
|
|||||||
n->val.val.str = $1;
|
n->val.val.str = $1;
|
||||||
$$ = lappend(lcons((Node *)n,NIL), $3);
|
$$ = lappend(lcons((Node *)n,NIL), $3);
|
||||||
}
|
}
|
||||||
| /* EMPTY */
|
| /*EMPTY*/
|
||||||
{ $$ = NIL; }
|
{ $$ = NIL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -4180,7 +4184,7 @@ extract_arg: datetime { $$ = $1; }
|
|||||||
|
|
||||||
position_list: position_expr IN position_expr
|
position_list: position_expr IN position_expr
|
||||||
{ $$ = makeList($3, $1, -1); }
|
{ $$ = makeList($3, $1, -1); }
|
||||||
| /* EMPTY */
|
| /*EMPTY*/
|
||||||
{ $$ = NIL; }
|
{ $$ = NIL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -4314,13 +4318,13 @@ substr_list: expr_list substr_from substr_for
|
|||||||
{
|
{
|
||||||
$$ = nconc(nconc($1,$2),$3);
|
$$ = nconc(nconc($1,$2),$3);
|
||||||
}
|
}
|
||||||
| /* EMPTY */
|
| /*EMPTY*/
|
||||||
{ $$ = NIL; }
|
{ $$ = NIL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
substr_from: FROM expr_list
|
substr_from: FROM expr_list
|
||||||
{ $$ = $2; }
|
{ $$ = $2; }
|
||||||
| /* EMPTY */
|
| /*EMPTY*/
|
||||||
{
|
{
|
||||||
A_Const *n = makeNode(A_Const);
|
A_Const *n = makeNode(A_Const);
|
||||||
n->val.type = T_Integer;
|
n->val.type = T_Integer;
|
||||||
@ -4331,7 +4335,7 @@ substr_from: FROM expr_list
|
|||||||
|
|
||||||
substr_for: FOR expr_list
|
substr_for: FOR expr_list
|
||||||
{ $$ = $2; }
|
{ $$ = $2; }
|
||||||
| /* EMPTY */
|
| /*EMPTY*/
|
||||||
{ $$ = NIL; }
|
{ $$ = NIL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -4379,6 +4383,94 @@ not_in_expr_nodes: AexprConst
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* Case clause
|
||||||
|
* Define SQL92-style case clause.
|
||||||
|
* Allow all four forms described in the standard:
|
||||||
|
* - Full specification
|
||||||
|
* CASE WHEN a = b THEN c ... ELSE d END
|
||||||
|
* - Implicit argument
|
||||||
|
* CASE a WHEN b THEN c ... ELSE d END
|
||||||
|
* - Conditional NULL
|
||||||
|
* NULLIF(x,y)
|
||||||
|
* same as CASE WHEN x = y THEN NULL ELSE x END
|
||||||
|
* - Conditional substitution from list, use first non-null argument
|
||||||
|
* COALESCE(a,b,...)
|
||||||
|
* same as CASE WHEN a IS NOT NULL THEN a WHEN b IS NOT NULL THEN b ... END
|
||||||
|
* - thomas 1998-11-09
|
||||||
|
*/
|
||||||
|
case_expr: CASE case_arg when_clause_list case_default END_TRANS
|
||||||
|
{
|
||||||
|
CaseExpr *c = makeNode(CaseExpr);
|
||||||
|
c->arg = $2;
|
||||||
|
c->args = $3;
|
||||||
|
c->defresult = $4;
|
||||||
|
$$ = (Node *)c;
|
||||||
|
}
|
||||||
|
| NULLIF '(' a_expr ',' a_expr ')'
|
||||||
|
{
|
||||||
|
CaseExpr *c = makeNode(CaseExpr);
|
||||||
|
CaseWhen *w = makeNode(CaseWhen);
|
||||||
|
c->args = lcons(w, NIL);
|
||||||
|
c->defresult = $3;
|
||||||
|
w->expr = makeA_Expr(OP, "=", $3, $5);
|
||||||
|
$$ = (Node *)c;
|
||||||
|
|
||||||
|
elog(NOTICE,"NULLIF() not yet fully implemented");
|
||||||
|
}
|
||||||
|
| COALESCE '(' expr_list ')'
|
||||||
|
{
|
||||||
|
CaseExpr *c = makeNode(CaseExpr);
|
||||||
|
CaseWhen *w;
|
||||||
|
List *l;
|
||||||
|
foreach (l,$3)
|
||||||
|
{
|
||||||
|
w = makeNode(CaseWhen);
|
||||||
|
w->expr = makeA_Expr(NOTNULL, NULL, lfirst(l), NULL);
|
||||||
|
w->result = lfirst(l);
|
||||||
|
c->args = lappend(c->args, w);
|
||||||
|
}
|
||||||
|
$$ = (Node *)c;
|
||||||
|
|
||||||
|
elog(NOTICE,"COALESCE() not yet fully implemented");
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
when_clause_list: when_clause_list when_clause
|
||||||
|
{ $$ = lappend($1, $2); }
|
||||||
|
| when_clause
|
||||||
|
{ $$ = lcons($1, NIL); }
|
||||||
|
;
|
||||||
|
|
||||||
|
when_clause: WHEN a_expr THEN a_expr_or_null
|
||||||
|
{
|
||||||
|
CaseWhen *w = makeNode(CaseWhen);
|
||||||
|
w->expr = $2;
|
||||||
|
w->result = $4;
|
||||||
|
$$ = (Node *)w;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
case_default: ELSE a_expr_or_null { $$ = $2; }
|
||||||
|
| /*EMPTY*/ { $$ = NULL; }
|
||||||
|
;
|
||||||
|
|
||||||
|
case_arg: attr opt_indirection
|
||||||
|
{
|
||||||
|
$1->indirection = $2;
|
||||||
|
$$ = (Node *)$1;
|
||||||
|
}
|
||||||
|
| ColId
|
||||||
|
{
|
||||||
|
/* could be a column name or a relation_name */
|
||||||
|
Ident *n = makeNode(Ident);
|
||||||
|
n->name = $1;
|
||||||
|
n->indirection = NULL;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| /*EMPTY*/
|
||||||
|
{ $$ = NULL; }
|
||||||
|
;
|
||||||
|
|
||||||
attr: relation_name '.' attrs
|
attr: relation_name '.' attrs
|
||||||
{
|
{
|
||||||
$$ = makeNode(Attr);
|
$$ = makeNode(Attr);
|
||||||
@ -4512,7 +4604,7 @@ res_target_el2: a_expr_or_null AS ColLabel
|
|||||||
;
|
;
|
||||||
|
|
||||||
opt_id: ColId { $$ = $1; }
|
opt_id: ColId { $$ = $1; }
|
||||||
| /* EMPTY */ { $$ = NULL; }
|
| /*EMPTY*/ { $$ = NULL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
relation_name: SpecialRuleRelation
|
relation_name: SpecialRuleRelation
|
||||||
@ -4723,12 +4815,16 @@ ColLabel: ColId { $$ = $1; }
|
|||||||
| ABORT_TRANS { $$ = "abort"; }
|
| ABORT_TRANS { $$ = "abort"; }
|
||||||
| ANALYZE { $$ = "analyze"; }
|
| ANALYZE { $$ = "analyze"; }
|
||||||
| BINARY { $$ = "binary"; }
|
| BINARY { $$ = "binary"; }
|
||||||
|
| CASE { $$ = "case"; }
|
||||||
| CLUSTER { $$ = "cluster"; }
|
| CLUSTER { $$ = "cluster"; }
|
||||||
|
| COALESCE { $$ = "coalesce"; }
|
||||||
| CONSTRAINT { $$ = "constraint"; }
|
| CONSTRAINT { $$ = "constraint"; }
|
||||||
| COPY { $$ = "copy"; }
|
| COPY { $$ = "copy"; }
|
||||||
| CROSS { $$ = "cross"; }
|
| CROSS { $$ = "cross"; }
|
||||||
| CURRENT { $$ = "current"; }
|
| CURRENT { $$ = "current"; }
|
||||||
| DO { $$ = "do"; }
|
| DO { $$ = "do"; }
|
||||||
|
| ELSE { $$ = "else"; }
|
||||||
|
| END_TRANS { $$ = "end"; }
|
||||||
| EXPLAIN { $$ = "explain"; }
|
| EXPLAIN { $$ = "explain"; }
|
||||||
| EXTEND { $$ = "extend"; }
|
| EXTEND { $$ = "extend"; }
|
||||||
| FALSE_P { $$ = "false"; }
|
| FALSE_P { $$ = "false"; }
|
||||||
@ -4740,6 +4836,7 @@ ColLabel: ColId { $$ = $1; }
|
|||||||
| MOVE { $$ = "move"; }
|
| MOVE { $$ = "move"; }
|
||||||
| NEW { $$ = "new"; }
|
| NEW { $$ = "new"; }
|
||||||
| NONE { $$ = "none"; }
|
| NONE { $$ = "none"; }
|
||||||
|
| NULLIF { $$ = "nullif"; }
|
||||||
| ORDER { $$ = "order"; }
|
| ORDER { $$ = "order"; }
|
||||||
| POSITION { $$ = "position"; }
|
| POSITION { $$ = "position"; }
|
||||||
| PRECISION { $$ = "precision"; }
|
| PRECISION { $$ = "precision"; }
|
||||||
@ -4747,10 +4844,12 @@ ColLabel: ColId { $$ = $1; }
|
|||||||
| SETOF { $$ = "setof"; }
|
| SETOF { $$ = "setof"; }
|
||||||
| SHOW { $$ = "show"; }
|
| SHOW { $$ = "show"; }
|
||||||
| TABLE { $$ = "table"; }
|
| TABLE { $$ = "table"; }
|
||||||
|
| THEN { $$ = "then"; }
|
||||||
| TRANSACTION { $$ = "transaction"; }
|
| TRANSACTION { $$ = "transaction"; }
|
||||||
| TRUE_P { $$ = "true"; }
|
| TRUE_P { $$ = "true"; }
|
||||||
| VACUUM { $$ = "vacuum"; }
|
| VACUUM { $$ = "vacuum"; }
|
||||||
| VERBOSE { $$ = "verbose"; }
|
| VERBOSE { $$ = "verbose"; }
|
||||||
|
| WHEN { $$ = "when"; }
|
||||||
;
|
;
|
||||||
|
|
||||||
SpecialRuleRelation: CURRENT
|
SpecialRuleRelation: CURRENT
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.48 1998/10/18 23:30:17 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.49 1998/12/04 15:34:29 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -51,12 +51,14 @@ static ScanKeyword ScanKeywords[] = {
|
|||||||
{"by", BY},
|
{"by", BY},
|
||||||
{"cache", CACHE},
|
{"cache", CACHE},
|
||||||
{"cascade", CASCADE},
|
{"cascade", CASCADE},
|
||||||
|
{"case", CASE},
|
||||||
{"cast", CAST},
|
{"cast", CAST},
|
||||||
{"char", CHAR},
|
{"char", CHAR},
|
||||||
{"character", CHARACTER},
|
{"character", CHARACTER},
|
||||||
{"check", CHECK},
|
{"check", CHECK},
|
||||||
{"close", CLOSE},
|
{"close", CLOSE},
|
||||||
{"cluster", CLUSTER},
|
{"cluster", CLUSTER},
|
||||||
|
{"coalesce", COALESCE},
|
||||||
{"collate", COLLATE},
|
{"collate", COLLATE},
|
||||||
{"column", COLUMN},
|
{"column", COLUMN},
|
||||||
{"commit", COMMIT},
|
{"commit", COMMIT},
|
||||||
@ -88,6 +90,7 @@ static ScanKeyword ScanKeywords[] = {
|
|||||||
{"double", DOUBLE},
|
{"double", DOUBLE},
|
||||||
{"drop", DROP},
|
{"drop", DROP},
|
||||||
{"each", EACH},
|
{"each", EACH},
|
||||||
|
{"else", ELSE},
|
||||||
{"encoding", ENCODING},
|
{"encoding", ENCODING},
|
||||||
{"end", END_TRANS},
|
{"end", END_TRANS},
|
||||||
{"execute", EXECUTE},
|
{"execute", EXECUTE},
|
||||||
@ -154,6 +157,7 @@ static ScanKeyword ScanKeywords[] = {
|
|||||||
{"notify", NOTIFY},
|
{"notify", NOTIFY},
|
||||||
{"notnull", NOTNULL},
|
{"notnull", NOTNULL},
|
||||||
{"null", NULL_P},
|
{"null", NULL_P},
|
||||||
|
{"nullif", NULLIF},
|
||||||
{"numeric", NUMERIC},
|
{"numeric", NUMERIC},
|
||||||
{"of", OF},
|
{"of", OF},
|
||||||
{"oids", OIDS},
|
{"oids", OIDS},
|
||||||
@ -201,6 +205,7 @@ static ScanKeyword ScanKeywords[] = {
|
|||||||
{"stdout", STDOUT},
|
{"stdout", STDOUT},
|
||||||
{"substring", SUBSTRING},
|
{"substring", SUBSTRING},
|
||||||
{"table", TABLE},
|
{"table", TABLE},
|
||||||
|
{"then", THEN},
|
||||||
{"time", TIME},
|
{"time", TIME},
|
||||||
{"timestamp", TIMESTAMP},
|
{"timestamp", TIMESTAMP},
|
||||||
{"timezone_hour", TIMEZONE_HOUR},
|
{"timezone_hour", TIMEZONE_HOUR},
|
||||||
@ -228,6 +233,7 @@ static ScanKeyword ScanKeywords[] = {
|
|||||||
{"verbose", VERBOSE},
|
{"verbose", VERBOSE},
|
||||||
{"version", VERSION},
|
{"version", VERSION},
|
||||||
{"view", VIEW},
|
{"view", VIEW},
|
||||||
|
{"when", WHEN},
|
||||||
{"where", WHERE},
|
{"where", WHERE},
|
||||||
{"with", WITH},
|
{"with", WITH},
|
||||||
{"work", WORK},
|
{"work", WORK},
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.9 1998/10/22 13:50:54 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.10 1998/12/04 15:34:30 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -342,7 +342,7 @@ TypeCategory(Oid inType)
|
|||||||
|
|
||||||
|
|
||||||
/* IsPreferredType()
|
/* IsPreferredType()
|
||||||
* Assign a category to the specified OID.
|
* Check if this type is a preferred type.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
IsPreferredType(CATEGORY category, Oid type)
|
IsPreferredType(CATEGORY category, Oid type)
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.36 1998/10/02 16:23:05 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.37 1998/12/04 15:34:30 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -29,6 +29,7 @@
|
|||||||
#include "parser/parse_node.h"
|
#include "parser/parse_node.h"
|
||||||
#include "parser/parse_relation.h"
|
#include "parser/parse_relation.h"
|
||||||
#include "parser/parse_target.h"
|
#include "parser/parse_target.h"
|
||||||
|
#include "parser/parse_coerce.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
static Node *parser_typecast(Value *expr, TypeName *typename, int32 atttypmod);
|
static Node *parser_typecast(Value *expr, TypeName *typename, int32 atttypmod);
|
||||||
@ -265,7 +266,9 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
|||||||
foreach(args, fn->args)
|
foreach(args, fn->args)
|
||||||
lfirst(args) = transformExpr(pstate, (Node *) lfirst(args), precedence);
|
lfirst(args) = transformExpr(pstate, (Node *) lfirst(args), precedence);
|
||||||
result = ParseFuncOrColumn(pstate,
|
result = ParseFuncOrColumn(pstate,
|
||||||
fn->funcname, fn->args, &pstate->p_last_resno,
|
fn->funcname,
|
||||||
|
fn->args,
|
||||||
|
&pstate->p_last_resno,
|
||||||
precedence);
|
precedence);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -332,6 +335,146 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case T_CaseExpr:
|
||||||
|
{
|
||||||
|
CaseExpr *c = (CaseExpr *) expr;
|
||||||
|
CaseWhen *w;
|
||||||
|
List *args;
|
||||||
|
Oid ptype;
|
||||||
|
CATEGORY pcategory;
|
||||||
|
|
||||||
|
/* transform the list of arguments */
|
||||||
|
foreach(args, c->args)
|
||||||
|
{
|
||||||
|
w = lfirst(args);
|
||||||
|
/* shorthand form was specified, so expand... */
|
||||||
|
if (c->arg != NULL)
|
||||||
|
{
|
||||||
|
A_Expr *a = makeNode(A_Expr);
|
||||||
|
a->oper = OP;
|
||||||
|
a->opname = "=";
|
||||||
|
a->lexpr = c->arg;
|
||||||
|
a->rexpr = w->expr;
|
||||||
|
w->expr = (Node *)a;
|
||||||
|
}
|
||||||
|
lfirst(args) = transformExpr(pstate, (Node *) w, precedence);
|
||||||
|
|
||||||
|
if (w->result == NULL)
|
||||||
|
{
|
||||||
|
A_Const *n = makeNode(A_Const);
|
||||||
|
n->val.type = T_Null;
|
||||||
|
w->result = (Node *)n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->defresult == NULL)
|
||||||
|
{
|
||||||
|
A_Const *n = makeNode(A_Const);
|
||||||
|
n->val.type = T_Null;
|
||||||
|
c->defresult = (Node *)n;
|
||||||
|
}
|
||||||
|
c->defresult = transformExpr(pstate, (Node *) c->defresult, precedence);
|
||||||
|
c->casetype = exprType(c->defresult);
|
||||||
|
|
||||||
|
/* now check types across result clauses... */
|
||||||
|
ptype = c->casetype;
|
||||||
|
pcategory = TypeCategory(ptype);
|
||||||
|
foreach(args, c->args)
|
||||||
|
{
|
||||||
|
Oid wtype;
|
||||||
|
|
||||||
|
w = lfirst(args);
|
||||||
|
wtype = exprType(w->result);
|
||||||
|
/* move on to next one if no new information... */
|
||||||
|
if (wtype && (wtype != UNKNOWNOID)
|
||||||
|
&& (wtype != ptype))
|
||||||
|
{
|
||||||
|
/* so far, only nulls so take anything... */
|
||||||
|
if (!ptype)
|
||||||
|
{
|
||||||
|
ptype = wtype;
|
||||||
|
pcategory = TypeCategory(ptype);
|
||||||
|
}
|
||||||
|
/* both types in different categories? then not much hope... */
|
||||||
|
else if ((TypeCategory(wtype) != pcategory)
|
||||||
|
|| ((TypeCategory(wtype) == USER_TYPE)
|
||||||
|
&& (TypeCategory(c->casetype) == USER_TYPE)))
|
||||||
|
{
|
||||||
|
elog(ERROR,"CASE/WHEN types '%s' and '%s' not matched",
|
||||||
|
typeidTypeName(c->casetype), typeidTypeName(wtype));
|
||||||
|
}
|
||||||
|
/* new one is preferred and can convert? then take it... */
|
||||||
|
else if (IsPreferredType(pcategory, wtype)
|
||||||
|
&& can_coerce_type(1, &ptype, &wtype))
|
||||||
|
{
|
||||||
|
ptype = wtype;
|
||||||
|
pcategory = TypeCategory(ptype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert default clause, if necessary */
|
||||||
|
if (c->casetype != ptype)
|
||||||
|
{
|
||||||
|
if (! c->casetype)
|
||||||
|
{
|
||||||
|
/* default clause is NULL,
|
||||||
|
* so assign preferred type from WHEN clauses... */
|
||||||
|
c->casetype = ptype;
|
||||||
|
}
|
||||||
|
else if (can_coerce_type(1, &c->casetype, &ptype))
|
||||||
|
{
|
||||||
|
c->defresult = coerce_type(pstate, c->defresult, c->casetype, ptype);
|
||||||
|
c->casetype = ptype;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
elog(ERROR,"CASE/ELSE unable to convert to type %s",
|
||||||
|
typeidTypeName(ptype));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert when clauses, if not null and if necessary */
|
||||||
|
foreach(args, c->args)
|
||||||
|
{
|
||||||
|
Oid wtype;
|
||||||
|
|
||||||
|
w = lfirst(args);
|
||||||
|
wtype = exprType(w->result);
|
||||||
|
/* only bother with conversion if not NULL and different type... */
|
||||||
|
if (wtype && (wtype != ptype))
|
||||||
|
{
|
||||||
|
if (can_coerce_type(1, &wtype, &ptype))
|
||||||
|
{
|
||||||
|
w->result = coerce_type(pstate, w->result, wtype, ptype);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
elog(ERROR,"CASE/WHEN unable to convert to type %s",
|
||||||
|
typeidTypeName(ptype));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = expr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case T_CaseWhen:
|
||||||
|
{
|
||||||
|
CaseWhen *w = (CaseWhen *) expr;
|
||||||
|
|
||||||
|
w->expr = transformExpr(pstate, (Node *) w->expr, precedence);
|
||||||
|
if (exprType(w->expr) != BOOLOID)
|
||||||
|
elog(ERROR,"WHEN clause must have a boolean result");
|
||||||
|
|
||||||
|
/* result is NULL for NULLIF() construct - thomas 1998-11-11 */
|
||||||
|
if (w->result != NULL)
|
||||||
|
w->result = transformExpr(pstate, (Node *) w->result, precedence);
|
||||||
|
result = expr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Some nodes do _not_ come from the original parse tree,
|
/* Some nodes do _not_ come from the original parse tree,
|
||||||
* but result from parser transformation in this phase.
|
* but result from parser transformation in this phase.
|
||||||
* At least one construct (BETWEEN/AND) puts the same nodes
|
* At least one construct (BETWEEN/AND) puts the same nodes
|
||||||
@ -423,6 +566,9 @@ exprType(Node *expr)
|
|||||||
{
|
{
|
||||||
Oid type = (Oid) 0;
|
Oid type = (Oid) 0;
|
||||||
|
|
||||||
|
if (!expr)
|
||||||
|
return type;
|
||||||
|
|
||||||
switch (nodeTag(expr))
|
switch (nodeTag(expr))
|
||||||
{
|
{
|
||||||
case T_Func:
|
case T_Func:
|
||||||
@ -452,6 +598,12 @@ exprType(Node *expr)
|
|||||||
case T_SubLink:
|
case T_SubLink:
|
||||||
type = BOOLOID;
|
type = BOOLOID;
|
||||||
break;
|
break;
|
||||||
|
case T_CaseExpr:
|
||||||
|
type = ((CaseExpr *) expr)->casetype;
|
||||||
|
break;
|
||||||
|
case T_CaseWhen:
|
||||||
|
type = exprType(((CaseWhen *) expr)->result);
|
||||||
|
break;
|
||||||
case T_Ident:
|
case T_Ident:
|
||||||
/* is this right? */
|
/* is this right? */
|
||||||
type = UNKNOWNOID;
|
type = UNKNOWNOID;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.30 1998/10/08 18:29:47 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.31 1998/12/04 15:34:30 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -39,6 +39,9 @@ static Node *SizeTargetExpr(ParseState *pstate,
|
|||||||
Oid attrtype,
|
Oid attrtype,
|
||||||
int32 attrtypmod);
|
int32 attrtypmod);
|
||||||
|
|
||||||
|
static TargetEntry *
|
||||||
|
MakeTargetEntryCase(ParseState *pstate,
|
||||||
|
ResTarget *res);
|
||||||
|
|
||||||
/* MakeTargetEntryIdent()
|
/* MakeTargetEntryIdent()
|
||||||
* Transforms an Ident Node to a Target Entry
|
* Transforms an Ident Node to a Target Entry
|
||||||
@ -53,11 +56,7 @@ static Node *SizeTargetExpr(ParseState *pstate,
|
|||||||
*/
|
*/
|
||||||
TargetEntry *
|
TargetEntry *
|
||||||
MakeTargetEntryIdent(ParseState *pstate,
|
MakeTargetEntryIdent(ParseState *pstate,
|
||||||
#if FALSE
|
|
||||||
Ident *ident,
|
|
||||||
#else
|
|
||||||
Node *node,
|
Node *node,
|
||||||
#endif
|
|
||||||
char **resname,
|
char **resname,
|
||||||
char *refname,
|
char *refname,
|
||||||
char *colname,
|
char *colname,
|
||||||
@ -77,7 +76,7 @@ MakeTargetEntryIdent(ParseState *pstate,
|
|||||||
pstate->p_insert_columns = lnext(pstate->p_insert_columns);
|
pstate->p_insert_columns = lnext(pstate->p_insert_columns);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
elog(ERROR, "insert: more expressions than target columns");
|
elog(ERROR, "INSERT has more expressions than target columns");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pstate->p_is_insert || pstate->p_is_update)
|
if (pstate->p_is_insert || pstate->p_is_update)
|
||||||
@ -105,7 +104,7 @@ MakeTargetEntryIdent(ParseState *pstate,
|
|||||||
{
|
{
|
||||||
rte = colnameRangeTableEntry(pstate, colname);
|
rte = colnameRangeTableEntry(pstate, colname);
|
||||||
if (rte == (RangeTblEntry *) NULL)
|
if (rte == (RangeTblEntry *) NULL)
|
||||||
elog(ERROR, "attribute %s not found", colname);
|
elog(ERROR, "Attribute %s not found", colname);
|
||||||
refname = rte->refname;
|
refname = rte->refname;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,14 +128,9 @@ MakeTargetEntryIdent(ParseState *pstate,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if TRUE
|
|
||||||
elog(ERROR, "Unable to convert %s to %s for column %s",
|
elog(ERROR, "Unable to convert %s to %s for column %s",
|
||||||
typeidTypeName(attrtype_id), typeidTypeName(attrtype_target),
|
typeidTypeName(attrtype_id), typeidTypeName(attrtype_target),
|
||||||
target_colname);
|
target_colname);
|
||||||
#else
|
|
||||||
elog(ERROR, "Type or size of %s(%d) does not match target column %s(%d)",
|
|
||||||
colname, attrtypmod, target_colname, attrtypmod_target);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,11 +146,7 @@ MakeTargetEntryIdent(ParseState *pstate,
|
|||||||
|
|
||||||
name = ((*resname != NULL) ? *resname : colname);
|
name = ((*resname != NULL) ? *resname : colname);
|
||||||
|
|
||||||
#if FALSE
|
|
||||||
expr = transformIdent(pstate, (Node *) ident, EXPR_COLUMN_FIRST);
|
|
||||||
#else
|
|
||||||
expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);
|
expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);
|
||||||
#endif
|
|
||||||
|
|
||||||
attrtype_target = exprType(expr);
|
attrtype_target = exprType(expr);
|
||||||
if (nodeTag(expr) == T_Var)
|
if (nodeTag(expr) == T_Var)
|
||||||
@ -187,7 +177,7 @@ MakeTargetEntryIdent(ParseState *pstate,
|
|||||||
* - thomas 1998-05-08
|
* - thomas 1998-05-08
|
||||||
*
|
*
|
||||||
* Added resjunk flag and made extern so that it can be use by GROUP/
|
* Added resjunk flag and made extern so that it can be use by GROUP/
|
||||||
* ORDER BY a function or expersion not in the target_list
|
* ORDER BY a function or expression not in the target_list
|
||||||
* - daveh@insightdist.com 1998-07-31
|
* - daveh@insightdist.com 1998-07-31
|
||||||
*/
|
*/
|
||||||
TargetEntry *
|
TargetEntry *
|
||||||
@ -207,7 +197,7 @@ MakeTargetEntryExpr(ParseState *pstate,
|
|||||||
Resdom *resnode;
|
Resdom *resnode;
|
||||||
|
|
||||||
if (expr == NULL)
|
if (expr == NULL)
|
||||||
elog(ERROR, "MakeTargetEntryExpr: invalid use of NULL expression");
|
elog(ERROR, "Invalid use of NULL expression (internal error)");
|
||||||
|
|
||||||
type_id = exprType(expr);
|
type_id = exprType(expr);
|
||||||
if (nodeTag(expr) == T_Var)
|
if (nodeTag(expr) == T_Var)
|
||||||
@ -251,9 +241,9 @@ MakeTargetEntryExpr(ParseState *pstate,
|
|||||||
expr = CoerceTargetExpr(pstate, expr, type_id, typelem);
|
expr = CoerceTargetExpr(pstate, expr, type_id, typelem);
|
||||||
|
|
||||||
if (!HeapTupleIsValid(expr))
|
if (!HeapTupleIsValid(expr))
|
||||||
elog(ERROR, "parser: attribute '%s' is of type '%s'"
|
elog(ERROR, "Attribute '%s' is of type '%s'"
|
||||||
" but expression is of type '%s'"
|
" but expression is of type '%s'"
|
||||||
"\n\tYou will need to rewrite or cast the expression",
|
"\n\tYou will need to rewrite or cast the expression",
|
||||||
colname,
|
colname,
|
||||||
typeidTypeName(attrtype),
|
typeidTypeName(attrtype),
|
||||||
typeidTypeName(type_id));
|
typeidTypeName(type_id));
|
||||||
@ -323,6 +313,45 @@ MakeTargetEntryExpr(ParseState *pstate,
|
|||||||
return makeTargetEntry(resnode, expr);
|
return makeTargetEntry(resnode, expr);
|
||||||
} /* MakeTargetEntryExpr() */
|
} /* MakeTargetEntryExpr() */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MakeTargetEntryCase()
|
||||||
|
* Make a TargetEntry from a case node.
|
||||||
|
*/
|
||||||
|
static TargetEntry *
|
||||||
|
MakeTargetEntryCase(ParseState *pstate,
|
||||||
|
ResTarget *res)
|
||||||
|
{
|
||||||
|
TargetEntry *tent;
|
||||||
|
CaseExpr *expr;
|
||||||
|
Resdom *resnode;
|
||||||
|
int resdomno;
|
||||||
|
Oid type_id;
|
||||||
|
int32 type_mod;
|
||||||
|
|
||||||
|
expr = (CaseExpr *)transformExpr(pstate, (Node *)res->val, EXPR_COLUMN_FIRST);
|
||||||
|
|
||||||
|
type_id = expr->casetype;
|
||||||
|
type_mod = -1;
|
||||||
|
handleTargetColname(pstate, &res->name, NULL, NULL);
|
||||||
|
if (res->name == NULL)
|
||||||
|
res->name = FigureColname((Node *)expr, res->val);
|
||||||
|
|
||||||
|
resdomno = pstate->p_last_resno++;
|
||||||
|
resnode = makeResdom((AttrNumber) resdomno,
|
||||||
|
(Oid) type_id,
|
||||||
|
type_mod,
|
||||||
|
res->name,
|
||||||
|
(Index) 0,
|
||||||
|
(Oid) 0,
|
||||||
|
0);
|
||||||
|
|
||||||
|
tent = makeNode(TargetEntry);
|
||||||
|
tent->resdom = resnode;
|
||||||
|
tent->expr = (Node *)expr;
|
||||||
|
|
||||||
|
return tent;
|
||||||
|
} /* MakeTargetEntryCase() */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MakeTargetEntryComplex()
|
* MakeTargetEntryComplex()
|
||||||
* Make a TargetEntry from a complex node.
|
* Make a TargetEntry from a complex node.
|
||||||
@ -351,7 +380,7 @@ MakeTargetEntryComplex(ParseState *pstate,
|
|||||||
Value *constval;
|
Value *constval;
|
||||||
|
|
||||||
if (exprType(expr) != UNKNOWNOID || !IsA(expr, Const))
|
if (exprType(expr) != UNKNOWNOID || !IsA(expr, Const))
|
||||||
elog(ERROR, "yyparse: string constant expected");
|
elog(ERROR, "String constant expected (internal error)");
|
||||||
|
|
||||||
val = (char *) textout((struct varlena *)
|
val = (char *) textout((struct varlena *)
|
||||||
((Const *) expr)->constvalue);
|
((Const *) expr)->constvalue);
|
||||||
@ -376,7 +405,7 @@ MakeTargetEntryComplex(ParseState *pstate,
|
|||||||
else
|
else
|
||||||
lindx[i] = 1;
|
lindx[i] = 1;
|
||||||
if (lindx[i] > uindx[i])
|
if (lindx[i] > uindx[i])
|
||||||
elog(ERROR, "yyparse: lower index cannot be greater than upper index");
|
elog(ERROR, "Lower index cannot be greater than upper index");
|
||||||
|
|
||||||
sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
|
sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
|
||||||
str += strlen(str);
|
str += strlen(str);
|
||||||
@ -388,7 +417,7 @@ MakeTargetEntryComplex(ParseState *pstate,
|
|||||||
resdomno = attnameAttNum(rd, res->name);
|
resdomno = attnameAttNum(rd, res->name);
|
||||||
ndims = attnumAttNelems(rd, resdomno);
|
ndims = attnumAttNelems(rd, resdomno);
|
||||||
if (i != ndims)
|
if (i != ndims)
|
||||||
elog(ERROR, "yyparse: array dimensions do not match");
|
elog(ERROR, "Array dimensions do not match");
|
||||||
|
|
||||||
constval = makeNode(Value);
|
constval = makeNode(Value);
|
||||||
constval->type = T_String;
|
constval->type = T_String;
|
||||||
@ -400,9 +429,9 @@ MakeTargetEntryComplex(ParseState *pstate,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *colname = res->name;
|
|
||||||
|
|
||||||
/* this is not an array assignment */
|
/* this is not an array assignment */
|
||||||
|
char *colname = res->name;
|
||||||
|
|
||||||
if (colname == NULL)
|
if (colname == NULL)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -540,6 +569,11 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
|||||||
tent = MakeTargetEntryComplex(pstate, res);
|
tent = MakeTargetEntryComplex(pstate, res);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case T_CaseExpr:
|
||||||
|
{
|
||||||
|
tent = MakeTargetEntryCase(pstate, res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case T_Attr:
|
case T_Attr:
|
||||||
{
|
{
|
||||||
bool expand_star = false;
|
bool expand_star = false;
|
||||||
@ -604,7 +638,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
/* internal error */
|
/* internal error */
|
||||||
elog(ERROR, "internal error: do not know how to transform targetlist");
|
elog(ERROR, "Unable to transform targetlist (internal error)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,7 +822,7 @@ ExpandAllTables(ParseState *pstate)
|
|||||||
|
|
||||||
/* this should not happen */
|
/* this should not happen */
|
||||||
if (rtable == NULL)
|
if (rtable == NULL)
|
||||||
elog(ERROR, "cannot expand: null p_rtable");
|
elog(ERROR, "Cannot expand tables; null p_rtable (internal error)");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* go through the range table and make a list of range table entries
|
* go through the range table and make a list of range table entries
|
||||||
@ -838,7 +872,7 @@ FigureColname(Node *expr, Node *resval)
|
|||||||
{
|
{
|
||||||
switch (nodeTag(expr))
|
switch (nodeTag(expr))
|
||||||
{
|
{
|
||||||
case T_Aggreg:
|
case T_Aggreg:
|
||||||
return (char *) ((Aggreg *) expr)->aggname;
|
return (char *) ((Aggreg *) expr)->aggname;
|
||||||
case T_Expr:
|
case T_Expr:
|
||||||
if (((Expr *) expr)->opType == FUNC_EXPR)
|
if (((Expr *) expr)->opType == FUNC_EXPR)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.25 1998/10/21 16:21:24 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.26 1998/12/04 15:34:36 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -39,7 +39,6 @@
|
|||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static RewriteInfo *gatherRewriteMeta(Query *parsetree,
|
static RewriteInfo *gatherRewriteMeta(Query *parsetree,
|
||||||
Query *rule_action,
|
Query *rule_action,
|
||||||
Node *rule_qual,
|
Node *rule_qual,
|
||||||
@ -55,17 +54,6 @@ static SubLink *modifyAggregMakeSublink(Expr *origexp, Query *parsetree);
|
|||||||
static void modifyAggregQual(Node **nodePtr, Query *parsetree);
|
static void modifyAggregQual(Node **nodePtr, Query *parsetree);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static Query *fireRIRrules(Query *parsetree);
|
static Query *fireRIRrules(Query *parsetree);
|
||||||
|
|
||||||
|
|
||||||
@ -293,6 +281,46 @@ rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_CaseExpr:
|
||||||
|
{
|
||||||
|
CaseExpr *exp = (CaseExpr *)node;
|
||||||
|
|
||||||
|
if (rangeTableEntry_used(
|
||||||
|
(Node *)(exp->args),
|
||||||
|
rt_index,
|
||||||
|
sublevels_up))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (rangeTableEntry_used(
|
||||||
|
(Node *)(exp->defresult),
|
||||||
|
rt_index,
|
||||||
|
sublevels_up))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_CaseWhen:
|
||||||
|
{
|
||||||
|
CaseWhen *when = (CaseWhen *)node;
|
||||||
|
|
||||||
|
if (rangeTableEntry_used(
|
||||||
|
(Node *)(when->expr),
|
||||||
|
rt_index,
|
||||||
|
sublevels_up))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (rangeTableEntry_used(
|
||||||
|
(Node *)(when->result),
|
||||||
|
rt_index,
|
||||||
|
sublevels_up))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case T_Query:
|
case T_Query:
|
||||||
{
|
{
|
||||||
Query *qry = (Query *)node;
|
Query *qry = (Query *)node;
|
||||||
@ -1055,10 +1083,12 @@ modifyAggregMakeSublink(Expr *origexp, Query *parsetree)
|
|||||||
Expr *exp = copyObject(origexp);
|
Expr *exp = copyObject(origexp);
|
||||||
|
|
||||||
if (nodeTag(nth(0, exp->args)) == T_Aggreg)
|
if (nodeTag(nth(0, exp->args)) == T_Aggreg)
|
||||||
|
{
|
||||||
if (nodeTag(nth(1, exp->args)) == T_Aggreg)
|
if (nodeTag(nth(1, exp->args)) == T_Aggreg)
|
||||||
elog(ERROR, "rewrite: comparision of 2 aggregate columns not supported");
|
elog(ERROR, "rewrite: comparision of 2 aggregate columns not supported");
|
||||||
else
|
else
|
||||||
elog(ERROR, "rewrite: aggregate column of view must be at rigth side in qual");
|
elog(ERROR, "rewrite: aggregate column of view must be at rigth side in qual");
|
||||||
|
}
|
||||||
|
|
||||||
aggreg = (Aggreg *)nth(1, exp->args);
|
aggreg = (Aggreg *)nth(1, exp->args);
|
||||||
target = (Var *)(aggreg->target);
|
target = (Var *)(aggreg->target);
|
||||||
@ -1189,6 +1219,33 @@ modifyAggregQual(Node **nodePtr, Query *parsetree)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_CaseExpr:
|
||||||
|
{
|
||||||
|
/* We're calling recursively,
|
||||||
|
* and this routine knows how to handle lists
|
||||||
|
* so let it do the work to handle the WHEN clauses... */
|
||||||
|
modifyAggregQual(
|
||||||
|
(Node **)(&(((CaseExpr *)node)->args)),
|
||||||
|
parsetree);
|
||||||
|
|
||||||
|
modifyAggregQual(
|
||||||
|
(Node **)(&(((CaseExpr *)node)->defresult)),
|
||||||
|
parsetree);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_CaseWhen:
|
||||||
|
{
|
||||||
|
modifyAggregQual(
|
||||||
|
(Node **)(&(((CaseWhen *)node)->expr)),
|
||||||
|
parsetree);
|
||||||
|
|
||||||
|
modifyAggregQual(
|
||||||
|
(Node **)(&(((CaseWhen *)node)->result)),
|
||||||
|
parsetree);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case T_Iter:
|
case T_Iter:
|
||||||
{
|
{
|
||||||
Iter *iter = (Iter *)node;
|
Iter *iter = (Iter *)node;
|
||||||
@ -1827,6 +1884,10 @@ fireRIRonSubselect(Node *node)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_CaseExpr:
|
||||||
|
case T_CaseWhen:
|
||||||
|
break;
|
||||||
|
|
||||||
case T_Query:
|
case T_Query:
|
||||||
{
|
{
|
||||||
Query *qry = (Query *)node;
|
Query *qry = (Query *)node;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: nodes.h,v 1.31 1998/10/01 02:04:01 tgl Exp $
|
* $Id: nodes.h,v 1.32 1998/12/04 15:34:44 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -213,11 +213,13 @@ typedef enum NodeTag
|
|||||||
T_SortClause,
|
T_SortClause,
|
||||||
T_GroupClause,
|
T_GroupClause,
|
||||||
T_SubSelect,
|
T_SubSelect,
|
||||||
T_JoinUsing
|
T_JoinUsing,
|
||||||
|
T_CaseExpr,
|
||||||
|
T_CaseWhen
|
||||||
} NodeTag;
|
} NodeTag;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The first field of a node of any type is gauranteed to be the NodeTag.
|
* The first field of a node of any type is guaranteed to be the NodeTag.
|
||||||
* Hence the type of any node can be gotten by casting it to Node. Declaring
|
* Hence the type of any node can be gotten by casting it to Node. Declaring
|
||||||
* a variable to be of Node * (instead of void *) can also facilitate
|
* a variable to be of Node * (instead of void *) can also facilitate
|
||||||
* debugging.
|
* debugging.
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parsenodes.h,v 1.61 1998/10/22 13:52:24 momjian Exp $
|
* $Id: parsenodes.h,v 1.62 1998/12/04 15:34:44 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -713,6 +713,28 @@ typedef struct A_Const
|
|||||||
TypeName *typename; /* typecast */
|
TypeName *typename; /* typecast */
|
||||||
} A_Const;
|
} A_Const;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CaseExpr - a CASE expression
|
||||||
|
*/
|
||||||
|
typedef struct CaseExpr
|
||||||
|
{
|
||||||
|
NodeTag type;
|
||||||
|
Oid casetype;
|
||||||
|
Node *arg; /* implicit equality comparison argument */
|
||||||
|
List *args; /* the arguments (list of WHEN clauses) */
|
||||||
|
Node *defresult; /* the default result (ELSE clause) */
|
||||||
|
} CaseExpr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CaseWhen - an argument to a CASE expression
|
||||||
|
*/
|
||||||
|
typedef struct CaseWhen
|
||||||
|
{
|
||||||
|
NodeTag type;
|
||||||
|
Node *expr; /* comparison expression */
|
||||||
|
Node *result; /* substitution result */
|
||||||
|
} CaseWhen;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ColumnDef - column definition (used in various creates)
|
* ColumnDef - column definition (used in various creates)
|
||||||
*/
|
*/
|
||||||
@ -777,7 +799,7 @@ typedef struct ResTarget
|
|||||||
} ResTarget;
|
} ResTarget;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ParamString - used in with clauses
|
* ParamString - used in WITH clauses
|
||||||
*/
|
*/
|
||||||
typedef struct ParamString
|
typedef struct ParamString
|
||||||
{
|
{
|
||||||
@ -797,7 +819,7 @@ typedef struct RelExpr
|
|||||||
} RelExpr;
|
} RelExpr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SortGroupBy - for order by clause
|
* SortGroupBy - for ORDER BY clause
|
||||||
*/
|
*/
|
||||||
typedef struct SortGroupBy
|
typedef struct SortGroupBy
|
||||||
{
|
{
|
||||||
@ -807,7 +829,7 @@ typedef struct SortGroupBy
|
|||||||
} SortGroupBy;
|
} SortGroupBy;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JoinUsing - for join using clause
|
* JoinUsing - for JOIN USING clause
|
||||||
*/
|
*/
|
||||||
typedef struct JoinUsing
|
typedef struct JoinUsing
|
||||||
{
|
{
|
||||||
@ -818,7 +840,7 @@ typedef struct JoinUsing
|
|||||||
} JoinUsing;
|
} JoinUsing;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RangeVar - range variable, used in from clauses
|
* RangeVar - range variable, used in FROM clauses
|
||||||
*/
|
*/
|
||||||
typedef struct RangeVar
|
typedef struct RangeVar
|
||||||
{
|
{
|
||||||
@ -828,7 +850,7 @@ typedef struct RangeVar
|
|||||||
} RangeVar;
|
} RangeVar;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IndexElem - index parameters (used in create index)
|
* IndexElem - index parameters (used in CREATE INDEX)
|
||||||
*/
|
*/
|
||||||
typedef struct IndexElem
|
typedef struct IndexElem
|
||||||
{
|
{
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: clauses.h,v 1.13 1998/09/01 04:36:53 momjian Exp $
|
* $Id: clauses.h,v 1.14 1998/12/04 15:34:49 thomas Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -34,6 +34,8 @@ extern Expr *get_notclausearg(Expr *notclause);
|
|||||||
extern bool and_clause(Node *clause);
|
extern bool and_clause(Node *clause);
|
||||||
extern Expr *make_andclause(List *andclauses);
|
extern Expr *make_andclause(List *andclauses);
|
||||||
|
|
||||||
|
extern bool case_clause(Node *clause);
|
||||||
|
|
||||||
extern List *pull_constant_clauses(List *quals, List **constantQual);
|
extern List *pull_constant_clauses(List *quals, List **constantQual);
|
||||||
extern void clause_get_relids_vars(Node *clause, List **relids, List **vars);
|
extern void clause_get_relids_vars(Node *clause, List **relids, List **vars);
|
||||||
extern int NumRelids(Node *clause);
|
extern int NumRelids(Node *clause);
|
||||||
|
Reference in New Issue
Block a user