mirror of
https://github.com/postgres/postgres.git
synced 2025-09-11 00:12:06 +03:00
COALESCE() and NULLIF() are now first-class expressions, not macros
that turn into CASE expressions. They evaluate their arguments at most once. Patch by Kris Jurka, review and (very light) editorializing by me.
This commit is contained in:
@@ -49,7 +49,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.106 2003/02/15 21:39:58 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.107 2003/02/16 02:30:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1468,7 +1468,8 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
*/
|
||||
if (IsA(node, FuncExpr) ||
|
||||
IsA(node, OpExpr) ||
|
||||
IsA(node, DistinctExpr))
|
||||
IsA(node, DistinctExpr) ||
|
||||
IsA(node, NullIfExpr))
|
||||
{
|
||||
total->per_tuple += cpu_operator_cost;
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.91 2003/01/20 18:54:52 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.92 2003/02/16 02:30:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -284,6 +284,8 @@ fix_expr_references_walker(Node *node, void *context)
|
||||
set_opfuncid((OpExpr *) node);
|
||||
else if (IsA(node, DistinctExpr))
|
||||
set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
|
||||
else if (IsA(node, NullIfExpr))
|
||||
set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
|
||||
else if (IsA(node, SubPlan))
|
||||
{
|
||||
SubPlan *sp = (SubPlan *) node;
|
||||
@@ -736,5 +738,7 @@ fix_opfuncids_walker(Node *node, void *context)
|
||||
set_opfuncid((OpExpr *) node);
|
||||
else if (IsA(node, DistinctExpr))
|
||||
set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
|
||||
else if (IsA(node, NullIfExpr))
|
||||
set_opfuncid((OpExpr *) node); /* rely on struct equivalence */
|
||||
return expression_tree_walker(node, fix_opfuncids_walker, context);
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.129 2003/02/09 06:56:27 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.130 2003/02/16 02:30:38 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -451,24 +451,22 @@ expression_returns_set_walker(Node *node, void *context)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
if (IsA(node, DistinctExpr))
|
||||
{
|
||||
DistinctExpr *expr = (DistinctExpr *) node;
|
||||
|
||||
if (expr->opretset)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
|
||||
/* Avoid recursion for some cases that can't return a set */
|
||||
if (IsA(node, BoolExpr))
|
||||
return false;
|
||||
if (IsA(node, Aggref))
|
||||
return false;
|
||||
if (IsA(node, DistinctExpr))
|
||||
return false;
|
||||
if (IsA(node, BoolExpr))
|
||||
return false;
|
||||
if (IsA(node, SubLink))
|
||||
return false;
|
||||
if (IsA(node, SubPlan))
|
||||
return false;
|
||||
if (IsA(node, CoalesceExpr))
|
||||
return false;
|
||||
if (IsA(node, NullIfExpr))
|
||||
return false;
|
||||
|
||||
return expression_tree_walker(node, expression_returns_set_walker,
|
||||
context);
|
||||
@@ -559,6 +557,14 @@ contain_mutable_functions_walker(Node *node, void *context)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
if (IsA(node, NullIfExpr))
|
||||
{
|
||||
NullIfExpr *expr = (NullIfExpr *) node;
|
||||
|
||||
if (op_volatile(expr->opno) != PROVOLATILE_IMMUTABLE)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
if (IsA(node, SubLink))
|
||||
{
|
||||
SubLink *sublink = (SubLink *) node;
|
||||
@@ -626,6 +632,14 @@ contain_volatile_functions_walker(Node *node, void *context)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
if (IsA(node, NullIfExpr))
|
||||
{
|
||||
NullIfExpr *expr = (NullIfExpr *) node;
|
||||
|
||||
if (op_volatile(expr->opno) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
if (IsA(node, SubLink))
|
||||
{
|
||||
SubLink *sublink = (SubLink *) node;
|
||||
@@ -707,6 +721,10 @@ contain_nonstrict_functions_walker(Node *node, void *context)
|
||||
}
|
||||
if (IsA(node, CaseExpr))
|
||||
return true;
|
||||
if (IsA(node, CoalesceExpr))
|
||||
return true;
|
||||
if (IsA(node, NullIfExpr))
|
||||
return true;
|
||||
if (IsA(node, NullTest))
|
||||
return true;
|
||||
if (IsA(node, BooleanTest))
|
||||
@@ -1446,6 +1464,39 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
|
||||
newcase->defresult = (Expr *) defresult;
|
||||
return (Node *) newcase;
|
||||
}
|
||||
if (IsA(node, CoalesceExpr))
|
||||
{
|
||||
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
|
||||
CoalesceExpr *newcoalesce;
|
||||
List *newargs = NIL;
|
||||
List *arg;
|
||||
|
||||
foreach(arg, coalesceexpr->args)
|
||||
{
|
||||
Node *e;
|
||||
|
||||
e = eval_const_expressions_mutator((Node *) lfirst(arg),
|
||||
active_fns);
|
||||
/*
|
||||
* We can remove null constants from the list.
|
||||
* For a non-null constant, if it has not been preceded by any
|
||||
* other non-null-constant expressions then that is the result.
|
||||
*/
|
||||
if (IsA(e, Const))
|
||||
{
|
||||
if (((Const *) e)->constisnull)
|
||||
continue; /* drop null constant */
|
||||
if (newargs == NIL)
|
||||
return e; /* first expr */
|
||||
}
|
||||
newargs = lappend(newargs, e);
|
||||
}
|
||||
|
||||
newcoalesce = makeNode(CoalesceExpr);
|
||||
newcoalesce->coalescetype = coalesceexpr->coalescetype;
|
||||
newcoalesce->args = newargs;
|
||||
return (Node *) newcoalesce;
|
||||
}
|
||||
|
||||
/*
|
||||
* For any node type not handled above, we recurse using
|
||||
@@ -2109,6 +2160,10 @@ expression_tree_walker(Node *node,
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_CoalesceExpr:
|
||||
return walker(((CoalesceExpr *) node)->args, context);
|
||||
case T_NullIfExpr:
|
||||
return walker(((NullIfExpr *) node)->args, context);
|
||||
case T_NullTest:
|
||||
return walker(((NullTest *) node)->arg, context);
|
||||
case T_BooleanTest:
|
||||
@@ -2481,6 +2536,26 @@ expression_tree_mutator(Node *node,
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_CoalesceExpr:
|
||||
{
|
||||
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
|
||||
CoalesceExpr *newnode;
|
||||
|
||||
FLATCOPY(newnode, coalesceexpr, CoalesceExpr);
|
||||
MUTATE(newnode->args, coalesceexpr->args, List *);
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_NullIfExpr:
|
||||
{
|
||||
NullIfExpr *expr = (NullIfExpr *) node;
|
||||
NullIfExpr *newnode;
|
||||
|
||||
FLATCOPY(newnode, expr, NullIfExpr);
|
||||
MUTATE(newnode->args, expr->args, List *);
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_NullTest:
|
||||
{
|
||||
NullTest *ntest = (NullTest *) node;
|
||||
|
Reference in New Issue
Block a user