aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/clauses.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r--src/backend/optimizer/util/clauses.c1114
1 files changed, 586 insertions, 528 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index a0d1b752bc4..ef317c5b223 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.115 2002/12/01 21:05:14 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.116 2002/12/12 15:49:32 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -70,84 +70,41 @@ static bool contain_mutable_functions_walker(Node *node, void *context);
static bool contain_volatile_functions_walker(Node *node, void *context);
static bool contain_nonstrict_functions_walker(Node *node, void *context);
static Node *eval_const_expressions_mutator(Node *node, List *active_fns);
-static Expr *simplify_op_or_func(Expr *expr, List *args, bool allow_inline,
- List *active_fns);
-static Expr *evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple);
-static Expr *inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple,
+static Expr *simplify_function(Oid funcid, List *args, bool allow_inline,
List *active_fns);
+static Expr *evaluate_function(Oid funcid, List *args, HeapTuple func_tuple);
+static Expr *inline_function(Oid funcid, List *args, HeapTuple func_tuple,
+ List *active_fns);
static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,
int *usecounts);
static Node *substitute_actual_parameters_mutator(Node *node,
substitute_actual_parameters_context *context);
-Expr *
-make_clause(int type, Node *oper, List *args)
-{
- Expr *expr = makeNode(Expr);
-
- switch (type)
- {
- case AND_EXPR:
- case OR_EXPR:
- case NOT_EXPR:
- expr->typeOid = BOOLOID;
- break;
- case OP_EXPR:
- case DISTINCT_EXPR:
- expr->typeOid = ((Oper *) oper)->opresulttype;
- break;
- case FUNC_EXPR:
- expr->typeOid = ((Func *) oper)->funcresulttype;
- break;
- default:
- elog(ERROR, "make_clause: unsupported type %d", type);
- break;
- }
- expr->opType = type;
- expr->oper = oper; /* ignored for AND, OR, NOT */
- expr->args = args;
- return expr;
-}
-
-
/*****************************************************************************
* OPERATOR clause functions
*****************************************************************************/
-
-/*
- * is_opclause
- *
- * Returns t iff the clause is an operator clause:
- * (op expr expr) or (op expr).
- */
-bool
-is_opclause(Node *clause)
-{
- return (clause != NULL &&
- IsA(clause, Expr) &&
- ((Expr *) clause)->opType == OP_EXPR);
-}
-
/*
* make_opclause
- * Creates a clause given its operator, left operand, and right
- * operand (pass NULL to create single-operand clause).
+ * Creates an operator clause given its operator info, left operand,
+ * and right operand (pass NULL to create single-operand clause).
*/
Expr *
-make_opclause(Oper *op, Var *leftop, Var *rightop)
+make_opclause(Oid opno, Oid opresulttype, bool opretset,
+ Expr *leftop, Expr *rightop)
{
- Expr *expr = makeNode(Expr);
+ OpExpr *expr = makeNode(OpExpr);
- expr->typeOid = op->opresulttype;
- expr->opType = OP_EXPR;
- expr->oper = (Node *) op;
+ expr->opno = opno;
+ expr->opfuncid = InvalidOid;
+ expr->opresulttype = opresulttype;
+ expr->opretset = opretset;
if (rightop)
expr->args = makeList2(leftop, rightop);
else
expr->args = makeList1(leftop);
- return expr;
+ return (Expr *) expr;
}
/*
@@ -163,8 +120,10 @@ make_opclause(Oper *op, Var *leftop, Var *rightop)
Var *
get_leftop(Expr *clause)
{
- if (clause->args != NULL)
- return lfirst(clause->args);
+ OpExpr *expr = (OpExpr *) clause;
+
+ if (expr->args != NULL)
+ return lfirst(expr->args);
else
return NULL;
}
@@ -178,124 +137,109 @@ get_leftop(Expr *clause)
Var *
get_rightop(Expr *clause)
{
- if (clause->args != NULL && lnext(clause->args) != NULL)
- return lfirst(lnext(clause->args));
+ OpExpr *expr = (OpExpr *) clause;
+
+ if (expr->args != NULL && lnext(expr->args) != NULL)
+ return lfirst(lnext(expr->args));
else
return NULL;
}
/*****************************************************************************
- * FUNC clause functions
+ * FUNCTION clause functions
*****************************************************************************/
/*
- * is_funcclause
- *
- * Returns t iff the clause is a function clause: (func { expr }).
- */
-bool
-is_funcclause(Node *clause)
-{
- return (clause != NULL &&
- IsA(clause, Expr) &&
- ((Expr *) clause)->opType == FUNC_EXPR);
-}
-
-/*
* make_funcclause
- *
- * Creates a function clause given the FUNC node and the functional
- * arguments.
+ * Creates a function clause given its function info and argument list.
*/
Expr *
-make_funcclause(Func *func, List *funcargs)
+make_funcclause(Oid funcid, Oid funcresulttype, bool funcretset,
+ CoercionForm funcformat, List *funcargs)
{
- Expr *expr = makeNode(Expr);
+ FuncExpr *expr = makeNode(FuncExpr);
- expr->typeOid = func->funcresulttype;
- expr->opType = FUNC_EXPR;
- expr->oper = (Node *) func;
+ expr->funcid = funcid;
+ expr->funcresulttype = funcresulttype;
+ expr->funcretset = funcretset;
+ expr->funcformat = funcformat;
expr->args = funcargs;
- return expr;
+ return (Expr *) expr;
}
/*****************************************************************************
- * OR clause functions
+ * NOT clause functions
*****************************************************************************/
/*
- * or_clause
+ * not_clause
*
- * Returns t iff the clause is an 'or' clause: (OR { expr }).
+ * Returns t iff this is a 'not' clause: (NOT expr).
*/
bool
-or_clause(Node *clause)
+not_clause(Node *clause)
{
return (clause != NULL &&
- IsA(clause, Expr) &&
- ((Expr *) clause)->opType == OR_EXPR);
+ IsA(clause, BoolExpr) &&
+ ((BoolExpr *) clause)->boolop == NOT_EXPR);
}
/*
- * make_orclause
+ * make_notclause
*
- * Creates an 'or' clause given a list of its subclauses.
+ * Create a 'not' clause given the expression to be negated.
*/
Expr *
-make_orclause(List *orclauses)
+make_notclause(Expr *notclause)
{
- Expr *expr = makeNode(Expr);
+ BoolExpr *expr = makeNode(BoolExpr);
- expr->typeOid = BOOLOID;
- expr->opType = OR_EXPR;
- expr->oper = NULL;
- expr->args = orclauses;
- return expr;
+ expr->boolop = NOT_EXPR;
+ expr->args = makeList1(notclause);
+ return (Expr *) expr;
}
-/*****************************************************************************
- * NOT clause functions
- *****************************************************************************/
-
/*
- * not_clause
+ * get_notclausearg
*
- * Returns t iff this is a 'not' clause: (NOT expr).
+ * Retrieve the clause within a 'not' clause
*/
-bool
-not_clause(Node *clause)
+Expr *
+get_notclausearg(Expr *notclause)
{
- return (clause != NULL &&
- IsA(clause, Expr) &&
- ((Expr *) clause)->opType == NOT_EXPR);
+ return lfirst(((BoolExpr *) notclause)->args);
}
+/*****************************************************************************
+ * OR clause functions
+ *****************************************************************************/
+
/*
- * make_notclause
+ * or_clause
*
- * Create a 'not' clause given the expression to be negated.
+ * Returns t iff the clause is an 'or' clause: (OR { expr }).
*/
-Expr *
-make_notclause(Expr *notclause)
+bool
+or_clause(Node *clause)
{
- Expr *expr = makeNode(Expr);
-
- expr->typeOid = BOOLOID;
- expr->opType = NOT_EXPR;
- expr->oper = NULL;
- expr->args = makeList1(notclause);
- return expr;
+ return (clause != NULL &&
+ IsA(clause, BoolExpr) &&
+ ((BoolExpr *) clause)->boolop == OR_EXPR);
}
/*
- * get_notclausearg
+ * make_orclause
*
- * Retrieve the clause within a 'not' clause
+ * Creates an 'or' clause given a list of its subclauses.
*/
Expr *
-get_notclausearg(Expr *notclause)
+make_orclause(List *orclauses)
{
- return lfirst(notclause->args);
+ BoolExpr *expr = makeNode(BoolExpr);
+
+ expr->boolop = OR_EXPR;
+ expr->args = orclauses;
+ return (Expr *) expr;
}
/*****************************************************************************
@@ -312,25 +256,23 @@ bool
and_clause(Node *clause)
{
return (clause != NULL &&
- IsA(clause, Expr) &&
- ((Expr *) clause)->opType == AND_EXPR);
+ IsA(clause, BoolExpr) &&
+ ((BoolExpr *) clause)->boolop == AND_EXPR);
}
/*
* make_andclause
*
- * Create an 'and' clause given its arguments in a list.
+ * Creates an 'and' clause given a list of its subclauses.
*/
Expr *
make_andclause(List *andclauses)
{
- Expr *expr = makeNode(Expr);
+ BoolExpr *expr = makeNode(BoolExpr);
- expr->typeOid = BOOLOID;
- expr->opType = AND_EXPR;
- expr->oper = NULL;
+ expr->boolop = AND_EXPR;
expr->args = andclauses;
- return expr;
+ return (Expr *) expr;
}
/*
@@ -382,7 +324,7 @@ make_ands_implicit(Expr *clause)
if (clause == NULL)
return NIL; /* NULL -> NIL list == TRUE */
else if (and_clause((Node *) clause))
- return clause->args;
+ return ((BoolExpr *) clause)->args;
else if (IsA(clause, Const) &&
!((Const *) clause)->constisnull &&
DatumGetBool(((Const *) clause)->constvalue))
@@ -476,7 +418,7 @@ pull_agg_clause_walker(Node *node, List **listptr)
* Complain if the aggregate's argument contains any aggregates;
* nested agg functions are semantically nonsensical.
*/
- if (contain_agg_clause(((Aggref *) node)->target))
+ if (contain_agg_clause((Node *) ((Aggref *) node)->target))
elog(ERROR, "Aggregate function calls may not be nested");
/*
@@ -512,38 +454,41 @@ expression_returns_set_walker(Node *node, void *context)
{
if (node == NULL)
return false;
- if (IsA(node, Expr))
+ if (IsA(node, FuncExpr))
{
- Expr *expr = (Expr *) node;
+ FuncExpr *expr = (FuncExpr *) node;
- switch (expr->opType)
- {
- case OP_EXPR:
- case DISTINCT_EXPR:
- if (((Oper *) expr->oper)->opretset)
- return true;
- /* else fall through to check args */
- break;
- case FUNC_EXPR:
- if (((Func *) expr->oper)->funcretset)
- return true;
- /* else fall through to check args */
- break;
- case OR_EXPR:
- case AND_EXPR:
- case NOT_EXPR:
- /* Booleans can't return a set, so no need to recurse */
- return false;
- case SUBPLAN_EXPR:
- /* Subplans can't presently return sets either */
- return false;
- }
+ if (expr->funcretset)
+ return true;
+ /* else fall through to check args */
+ }
+ if (IsA(node, OpExpr))
+ {
+ OpExpr *expr = (OpExpr *) node;
+
+ if (expr->opretset)
+ 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 other cases that can't return a set */
+
+ /* 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, SubLink))
return false;
+ if (IsA(node, SubPlanExpr))
+ return false;
+
return expression_tree_walker(node, expression_returns_set_walker,
context);
}
@@ -574,7 +519,8 @@ contain_subplans_walker(Node *node, void *context)
{
if (node == NULL)
return false;
- if (is_subplan(node) || IsA(node, SubLink))
+ if (IsA(node, SubPlanExpr) ||
+ IsA(node, SubLink))
return true; /* abort the tree traversal and return
* true */
return expression_tree_walker(node, contain_subplans_walker, context);
@@ -584,8 +530,8 @@ contain_subplans_walker(Node *node, void *context)
* pull_subplans
* Recursively pulls all subplans from an expression tree.
*
- * Returns list of subplan nodes found. Note the nodes themselves are not
- * copied, only referenced.
+ * Returns list of SubPlanExpr nodes found. Note the nodes themselves
+ * are not copied, only referenced.
*/
List *
pull_subplans(Node *clause)
@@ -603,7 +549,7 @@ pull_subplans_walker(Node *node, List **listptr)
return false;
if (is_subplan(node))
{
- *listptr = lappend(*listptr, ((Expr *) node)->oper);
+ *listptr = lappend(*listptr, node);
/* fall through to check args to subplan */
}
return expression_tree_walker(node, pull_subplans_walker,
@@ -710,7 +656,7 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
*/
List *t;
- foreach(t, ((Expr *) node)->args)
+ foreach(t, ((SubPlanExpr *) node)->args)
{
Node *thisarg = lfirst(t);
Var *var;
@@ -789,24 +735,29 @@ contain_mutable_functions_walker(Node *node, void *context)
{
if (node == NULL)
return false;
- if (IsA(node, Expr))
+ if (IsA(node, FuncExpr))
{
- Expr *expr = (Expr *) node;
+ FuncExpr *expr = (FuncExpr *) node;
- switch (expr->opType)
- {
- case OP_EXPR:
- case DISTINCT_EXPR:
- if (op_volatile(((Oper *) expr->oper)->opno) != PROVOLATILE_IMMUTABLE)
- return true;
- break;
- case FUNC_EXPR:
- if (func_volatile(((Func *) expr->oper)->funcid) != PROVOLATILE_IMMUTABLE)
- return true;
- break;
- default:
- break;
- }
+ if (func_volatile(expr->funcid) != PROVOLATILE_IMMUTABLE)
+ return true;
+ /* else fall through to check args */
+ }
+ if (IsA(node, OpExpr))
+ {
+ OpExpr *expr = (OpExpr *) node;
+
+ if (op_volatile(expr->opno) != PROVOLATILE_IMMUTABLE)
+ return true;
+ /* else fall through to check args */
+ }
+ if (IsA(node, DistinctExpr))
+ {
+ DistinctExpr *expr = (DistinctExpr *) node;
+
+ if (op_volatile(expr->opno) != PROVOLATILE_IMMUTABLE)
+ return true;
+ /* else fall through to check args */
}
return expression_tree_walker(node, contain_mutable_functions_walker,
context);
@@ -839,24 +790,29 @@ contain_volatile_functions_walker(Node *node, void *context)
{
if (node == NULL)
return false;
- if (IsA(node, Expr))
+ if (IsA(node, FuncExpr))
{
- Expr *expr = (Expr *) node;
+ FuncExpr *expr = (FuncExpr *) node;
- switch (expr->opType)
- {
- case OP_EXPR:
- case DISTINCT_EXPR:
- if (op_volatile(((Oper *) expr->oper)->opno) == PROVOLATILE_VOLATILE)
- return true;
- break;
- case FUNC_EXPR:
- if (func_volatile(((Func *) expr->oper)->funcid) == PROVOLATILE_VOLATILE)
- return true;
- break;
- default:
- break;
- }
+ if (func_volatile(expr->funcid) == PROVOLATILE_VOLATILE)
+ return true;
+ /* else fall through to check args */
+ }
+ if (IsA(node, OpExpr))
+ {
+ OpExpr *expr = (OpExpr *) node;
+
+ if (op_volatile(expr->opno) == PROVOLATILE_VOLATILE)
+ return true;
+ /* else fall through to check args */
+ }
+ if (IsA(node, DistinctExpr))
+ {
+ DistinctExpr *expr = (DistinctExpr *) node;
+
+ if (op_volatile(expr->opno) == PROVOLATILE_VOLATILE)
+ return true;
+ /* else fall through to check args */
}
return expression_tree_walker(node, contain_volatile_functions_walker,
context);
@@ -876,7 +832,7 @@ contain_volatile_functions_walker(Node *node, void *context)
*
* XXX we do not examine sublinks/subplans to see if they contain uses of
* nonstrict functions. It's not real clear if that is correct or not...
- * for the current usage it does not matter, since inline_op_or_func()
+ * for the current usage it does not matter, since inline_function()
* rejects cases with sublinks.
*/
bool
@@ -890,23 +846,33 @@ contain_nonstrict_functions_walker(Node *node, void *context)
{
if (node == NULL)
return false;
- if (IsA(node, Expr))
+ if (IsA(node, FuncExpr))
+ {
+ FuncExpr *expr = (FuncExpr *) node;
+
+ if (!func_strict(expr->funcid))
+ return true;
+ /* else fall through to check args */
+ }
+ if (IsA(node, OpExpr))
+ {
+ OpExpr *expr = (OpExpr *) node;
+
+ if (!op_strict(expr->opno))
+ return true;
+ /* else fall through to check args */
+ }
+ if (IsA(node, DistinctExpr))
+ {
+ /* IS DISTINCT FROM is inherently non-strict */
+ return true;
+ }
+ if (IsA(node, BoolExpr))
{
- Expr *expr = (Expr *) node;
+ BoolExpr *expr = (BoolExpr *) node;
- switch (expr->opType)
+ switch (expr->boolop)
{
- case OP_EXPR:
- if (!op_strict(((Oper *) expr->oper)->opno))
- return true;
- break;
- case DISTINCT_EXPR:
- /* IS DISTINCT FROM is inherently non-strict */
- return true;
- case FUNC_EXPR:
- if (!func_strict(((Func *) expr->oper)->funcid))
- return true;
- break;
case OR_EXPR:
case AND_EXPR:
/* OR, AND are inherently non-strict */
@@ -1147,39 +1113,28 @@ NumRelids(Node *clause)
* XXX the clause is destructively modified!
*/
void
-CommuteClause(Expr *clause)
+CommuteClause(OpExpr *clause)
{
Oid opoid;
- HeapTuple optup;
- Form_pg_operator commuTup;
- Oper *commu;
Node *temp;
- if (!is_opclause((Node *) clause) ||
+ if (!is_opclause(clause) ||
length(clause->args) != 2)
elog(ERROR, "CommuteClause: applied to non-binary-operator clause");
- opoid = ((Oper *) clause->oper)->opno;
-
- optup = SearchSysCache(OPEROID,
- ObjectIdGetDatum(get_commutator(opoid)),
- 0, 0, 0);
- if (!HeapTupleIsValid(optup))
- elog(ERROR, "CommuteClause: no commutator for operator %u", opoid);
-
- commuTup = (Form_pg_operator) GETSTRUCT(optup);
+ opoid = get_commutator(clause->opno);
- commu = makeOper(HeapTupleGetOid(optup),
- commuTup->oprcode,
- commuTup->oprresult,
- ((Oper *) clause->oper)->opretset);
-
- ReleaseSysCache(optup);
+ if (!OidIsValid(opoid))
+ elog(ERROR, "CommuteClause: no commutator for operator %u",
+ clause->opno);
/*
- * re-form the clause in-place!
+ * modify the clause in-place!
*/
- clause->oper = (Node *) commu;
+ clause->opno = opoid;
+ clause->opfuncid = InvalidOid;
+ /* opresulttype and opretset are assumed not to change */
+
temp = lfirst(clause->args);
lfirst(clause->args) = lsecond(clause->args);
lsecond(clause->args) = temp;
@@ -1223,15 +1178,94 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
{
if (node == NULL)
return NULL;
- if (IsA(node, Expr))
+ if (IsA(node, FuncExpr))
{
- Expr *expr = (Expr *) node;
+ FuncExpr *expr = (FuncExpr *) node;
List *args;
- Const *const_input;
- Expr *newexpr;
+ Expr *simple;
+ FuncExpr *newexpr;
+
+ /*
+ * Reduce constants in the FuncExpr's arguments. We know args is
+ * either NIL or a List node, so we can call
+ * expression_tree_mutator directly rather than recursing to self.
+ */
+ args = (List *) expression_tree_mutator((Node *) expr->args,
+ eval_const_expressions_mutator,
+ (void *) active_fns);
+ /*
+ * Code for op/func reduction is pretty bulky, so split it out
+ * as a separate function.
+ */
+ simple = simplify_function(expr->funcid, args, true, active_fns);
+ if (simple) /* successfully simplified it */
+ return (Node *) simple;
+ /*
+ * The expression cannot be simplified any further, so build and
+ * return a replacement FuncExpr node using the possibly-simplified
+ * arguments.
+ */
+ newexpr = makeNode(FuncExpr);
+ newexpr->funcid = expr->funcid;
+ newexpr->funcresulttype = expr->funcresulttype;
+ newexpr->funcretset = expr->funcretset;
+ newexpr->funcformat = expr->funcformat;
+ newexpr->args = args;
+ return (Node *) newexpr;
+ }
+ if (IsA(node, OpExpr))
+ {
+ OpExpr *expr = (OpExpr *) node;
+ List *args;
+ Expr *simple;
+ OpExpr *newexpr;
/*
- * Reduce constants in the Expr's arguments. We know args is
+ * Reduce constants in the OpExpr's arguments. We know args is
+ * either NIL or a List node, so we can call
+ * expression_tree_mutator directly rather than recursing to self.
+ */
+ args = (List *) expression_tree_mutator((Node *) expr->args,
+ eval_const_expressions_mutator,
+ (void *) active_fns);
+ /*
+ * Need to get OID of underlying function. Okay to scribble on
+ * input to this extent.
+ */
+ set_opfuncid(expr);
+ /*
+ * Code for op/func reduction is pretty bulky, so split it out
+ * as a separate function.
+ */
+ simple = simplify_function(expr->opfuncid, args, true, active_fns);
+ if (simple) /* successfully simplified it */
+ return (Node *) simple;
+ /*
+ * The expression cannot be simplified any further, so build and
+ * return a replacement OpExpr node using the possibly-simplified
+ * arguments.
+ */
+ newexpr = makeNode(OpExpr);
+ newexpr->opno = expr->opno;
+ newexpr->opfuncid = expr->opfuncid;
+ newexpr->opresulttype = expr->opresulttype;
+ newexpr->opretset = expr->opretset;
+ newexpr->args = args;
+ return (Node *) newexpr;
+ }
+ if (IsA(node, DistinctExpr))
+ {
+ DistinctExpr *expr = (DistinctExpr *) node;
+ List *args;
+ List *arg;
+ bool has_null_input = false;
+ bool all_null_input = true;
+ bool has_nonconst_input = false;
+ Expr *simple;
+ DistinctExpr *newexpr;
+
+ /*
+ * Reduce constants in the DistinctExpr's arguments. We know args is
* either NIL or a List node, so we can call
* expression_tree_mutator directly rather than recursing to self.
*/
@@ -1239,76 +1273,83 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
eval_const_expressions_mutator,
(void *) active_fns);
- switch (expr->opType)
+ /*
+ * We must do our own check for NULLs because
+ * DistinctExpr has different results for NULL input
+ * than the underlying operator does.
+ */
+ foreach(arg, args)
{
- case OP_EXPR:
- case FUNC_EXPR:
+ if (IsA(lfirst(arg), Const))
+ {
+ has_null_input |= ((Const *) lfirst(arg))->constisnull;
+ all_null_input &= ((Const *) lfirst(arg))->constisnull;
+ }
+ else
+ has_nonconst_input = true;
+ }
- /*
- * Code for op/func case is pretty bulky, so split it out
- * as a separate function.
- */
- newexpr = simplify_op_or_func(expr, args,
- true, active_fns);
- if (newexpr) /* successfully simplified it */
- return (Node *) newexpr;
+ /* all constants? then can optimize this out */
+ if (!has_nonconst_input)
+ {
+ /* all nulls? then not distinct */
+ if (all_null_input)
+ return MAKEBOOLCONST(false, false);
- /*
- * else fall out to build new Expr node with simplified
- * args
- */
- break;
- case DISTINCT_EXPR:
- {
- List *arg;
- bool has_null_input = false;
- bool all_null_input = true;
- bool has_nonconst_input = false;
+ /* one null? then distinct */
+ if (has_null_input)
+ return MAKEBOOLCONST(true, false);
- /*
- * We must do our own check for NULLs because
- * DISTINCT_EXPR has different results for NULL input
- * than the underlying operator does.
- */
- foreach(arg, args)
- {
- if (IsA(lfirst(arg), Const))
- {
- has_null_input |= ((Const *) lfirst(arg))->constisnull;
- all_null_input &= ((Const *) lfirst(arg))->constisnull;
- }
- else
- has_nonconst_input = true;
- }
+ /* otherwise try to evaluate the '=' operator */
+ /* (NOT okay to try to inline it, though!) */
- /* all constants? then can optimize this out */
- if (!has_nonconst_input)
- {
- /* all nulls? then not distinct */
- if (all_null_input)
- return MAKEBOOLCONST(false, false);
-
- /* one null? then distinct */
- if (has_null_input)
- return MAKEBOOLCONST(true, false);
-
- /* otherwise try to evaluate the '=' operator */
- /* (NOT okay to try to inline it, though!) */
- newexpr = simplify_op_or_func(expr, args,
- false, active_fns);
- if (newexpr) /* successfully simplified it */
- return (Node *) newexpr;
- }
+ /*
+ * Need to get OID of underlying function. Okay to scribble on
+ * input to this extent.
+ */
+ set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
+ /*
+ * Code for op/func reduction is pretty bulky, so split it out
+ * as a separate function.
+ */
+ simple = simplify_function(expr->opfuncid, args,
+ false, active_fns);
+ if (simple) /* successfully simplified it */
+ return (Node *) simple;
+ }
- /*
- * else fall out to build new Expr node with simplified
- * args
- */
- break;
- }
+ /*
+ * The expression cannot be simplified any further, so build and
+ * return a replacement DistinctExpr node using the
+ * possibly-simplified arguments.
+ */
+ newexpr = makeNode(DistinctExpr);
+ newexpr->opno = expr->opno;
+ newexpr->opfuncid = expr->opfuncid;
+ newexpr->opresulttype = expr->opresulttype;
+ newexpr->opretset = expr->opretset;
+ newexpr->args = args;
+ return (Node *) newexpr;
+ }
+ if (IsA(node, BoolExpr))
+ {
+ BoolExpr *expr = (BoolExpr *) node;
+ List *args;
+ Const *const_input;
+
+ /*
+ * Reduce constants in the BoolExpr's arguments. We know args is
+ * either NIL or a List node, so we can call
+ * expression_tree_mutator directly rather than recursing to self.
+ */
+ args = (List *) expression_tree_mutator((Node *) expr->args,
+ eval_const_expressions_mutator,
+ (void *) active_fns);
+
+ switch (expr->boolop)
+ {
case OR_EXPR:
{
-
/*----------
* OR arguments are handled as follows:
* non constant: keep
@@ -1361,7 +1402,6 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
}
case AND_EXPR:
{
-
/*----------
* AND arguments are handled as follows:
* non constant: keep
@@ -1414,47 +1454,34 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
}
case NOT_EXPR:
Assert(length(args) == 1);
- if (!IsA(lfirst(args), Const))
- break;
- const_input = (Const *) lfirst(args);
- /* NOT NULL => NULL */
- if (const_input->constisnull)
- return MAKEBOOLCONST(false, true);
- /* otherwise pretty easy */
- return MAKEBOOLCONST(!DatumGetBool(const_input->constvalue),
- false);
- case SUBPLAN_EXPR:
-
- /*
- * Return a SubPlan unchanged --- too late to do anything
- * with it. The arglist simplification above was wasted
- * work (the list probably only contains Var nodes
- * anyway).
- *
- * XXX should we elog() here instead? Probably this routine
- * should never be invoked after SubPlan creation.
- */
- return (Node *) expr;
+ if (IsA(lfirst(args), Const))
+ {
+ const_input = (Const *) lfirst(args);
+ /* NOT NULL => NULL */
+ if (const_input->constisnull)
+ return MAKEBOOLCONST(false, true);
+ /* otherwise pretty easy */
+ return MAKEBOOLCONST(!DatumGetBool(const_input->constvalue),
+ false);
+ }
+ /* Else we still need a NOT node */
+ return (Node *) make_notclause(lfirst(args));
default:
- elog(ERROR, "eval_const_expressions: unexpected opType %d",
- (int) expr->opType);
+ elog(ERROR, "eval_const_expressions: unexpected boolop %d",
+ (int) expr->boolop);
break;
}
-
+ }
+ if (IsA(node, SubPlanExpr))
+ {
/*
- * If we break out of the above switch on opType, then the
- * expression cannot be simplified any further, so build and
- * return a replacement Expr node using the possibly-simplified
- * arguments and the original oper node. Can't use make_clause()
- * here because we want to be sure the typeOid field is
- * preserved...
+ * Return a SubPlanExpr unchanged --- too late to do anything
+ * with it.
+ *
+ * XXX should we elog() here instead? Probably this routine
+ * should never be invoked after SubPlanExpr creation.
*/
- newexpr = makeNode(Expr);
- newexpr->typeOid = expr->typeOid;
- newexpr->opType = expr->opType;
- newexpr->oper = expr->oper;
- newexpr->args = args;
- return (Node *) newexpr;
+ return node;
}
if (IsA(node, RelabelType))
{
@@ -1466,14 +1493,15 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
RelabelType *relabel = (RelabelType *) node;
Node *arg;
- arg = eval_const_expressions_mutator(relabel->arg, active_fns);
+ arg = eval_const_expressions_mutator((Node *) relabel->arg,
+ active_fns);
/*
* If we find stacked RelabelTypes (eg, from foo :: int :: oid) we
* can discard all but the top one.
*/
while (arg && IsA(arg, RelabelType))
- arg = ((RelabelType *) arg)->arg;
+ arg = (Node *) ((RelabelType *) arg)->arg;
if (arg && IsA(arg, Const))
{
@@ -1493,7 +1521,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
{
RelabelType *newrelabel = makeNode(RelabelType);
- newrelabel->arg = arg;
+ newrelabel->arg = (Expr *) arg;
newrelabel->resulttype = relabel->resulttype;
newrelabel->resulttypmod = relabel->resulttypmod;
return (Node *) newrelabel;
@@ -1545,7 +1573,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* alternative, the CASE reduces to just this alternative.
*/
if (newargs == NIL)
- return casewhen->result;
+ return (Node *) casewhen->result;
/*
* Otherwise, add it to the list, and drop all the rest.
@@ -1555,7 +1583,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
}
/* Simplify the default result */
- defresult = eval_const_expressions_mutator(caseexpr->defresult,
+ defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult,
active_fns);
/*
@@ -1569,7 +1597,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
newcase->casetype = caseexpr->casetype;
newcase->arg = NULL;
newcase->args = newargs;
- newcase->defresult = defresult;
+ newcase->defresult = (Expr *) defresult;
return (Node *) newcase;
}
@@ -1585,19 +1613,18 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
}
/*
- * Subroutine for eval_const_expressions: try to simplify an op or func
+ * Subroutine for eval_const_expressions: try to simplify a function call
+ * (which might originally have been an operator; we don't care)
*
- * Inputs are the op or func Expr node, and the pre-simplified argument list;
+ * Inputs are the function OID and the pre-simplified argument list;
* also a list of already-active inline function expansions.
*
* Returns a simplified expression if successful, or NULL if cannot
- * simplify the op/func.
+ * simplify the function call.
*/
static Expr *
-simplify_op_or_func(Expr *expr, List *args, bool allow_inline,
- List *active_fns)
+simplify_function(Oid funcid, List *args, bool allow_inline, List *active_fns)
{
- Oid funcid;
HeapTuple func_tuple;
Expr *newexpr;
@@ -1609,30 +1636,16 @@ simplify_op_or_func(Expr *expr, List *args, bool allow_inline,
* to the function's pg_proc tuple, so fetch it just once to use in both
* attempts.
*/
- if (expr->opType == FUNC_EXPR)
- {
- Func *func = (Func *) expr->oper;
-
- funcid = func->funcid;
- }
- else /* OP_EXPR or DISTINCT_EXPR */
- {
- Oper *oper = (Oper *) expr->oper;
-
- replace_opid(oper); /* OK to scribble on input to this extent */
- funcid = oper->opid;
- }
-
func_tuple = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
if (!HeapTupleIsValid(func_tuple))
elog(ERROR, "Function OID %u does not exist", funcid);
- newexpr = evaluate_op_or_func(expr, args, func_tuple);
+ newexpr = evaluate_function(funcid, args, func_tuple);
if (!newexpr && allow_inline)
- newexpr = inline_op_or_func(expr, args, func_tuple, active_fns);
+ newexpr = inline_function(funcid, args, func_tuple, active_fns);
ReleaseSysCache(func_tuple);
@@ -1640,17 +1653,17 @@ simplify_op_or_func(Expr *expr, List *args, bool allow_inline,
}
/*
- * evaluate_op_or_func: try to pre-evaluate an op or func
+ * evaluate_function: try to pre-evaluate a function call
*
* We can do this if the function is strict and has any constant-null inputs
* (just return a null constant), or if the function is immutable and has all
* constant inputs (call it and return the result as a Const node).
*
* Returns a simplified expression if successful, or NULL if cannot
- * simplify the op/func.
+ * simplify the function.
*/
static Expr *
-evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple)
+evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
Oid result_typeid = funcform->prorettype;
@@ -1658,7 +1671,7 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple)
bool resultTypByVal;
bool has_nonconst_input = false;
bool has_null_input = false;
- Expr *newexpr;
+ FuncExpr *newexpr;
ExprContext *econtext;
Datum const_val;
bool const_is_null;
@@ -1705,21 +1718,20 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple)
* We use the executor's routine ExecEvalExpr() to avoid duplication of
* code and ensure we get the same result as the executor would get.
*
- * Build a new Expr node containing the already-simplified arguments.
- * The only other setup needed here is the replace_opid() that
- * simplify_op_or_func already did for the OP_EXPR/DISTINCT_EXPR case.
+ * Build a new FuncExpr node containing the already-simplified arguments.
*/
- newexpr = makeNode(Expr);
- newexpr->typeOid = expr->typeOid;
- newexpr->opType = expr->opType;
- newexpr->oper = expr->oper;
+ newexpr = makeNode(FuncExpr);
+ newexpr->funcid = funcid;
+ newexpr->funcresulttype = result_typeid;
+ newexpr->funcretset = false;
+ newexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */
newexpr->args = args;
/* Get info needed about result datatype */
get_typlenbyval(result_typeid, &resultTypLen, &resultTypByVal);
/*
- * It is OK to pass a dummy econtext because none of the
+ * It is OK to use a dummy econtext because none of the
* ExecEvalExpr() code used in this situation will use econtext. That
* might seem fortuitous, but it's not so unreasonable --- a constant
* expression does not depend on context, by definition, n'est ce pas?
@@ -1745,7 +1757,7 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple)
}
/*
- * inline_op_or_func: try to expand inline an op or func
+ * inline_function: try to expand a function call inline
*
* If the function is a sufficiently simple SQL-language function
* (just "SELECT expression"), then we can inline it and avoid the rather
@@ -1763,14 +1775,13 @@ evaluate_op_or_func(Expr *expr, List *args, HeapTuple func_tuple)
* functions by inlining them.
*
* Returns a simplified expression if successful, or NULL if cannot
- * simplify the op/func.
+ * simplify the function.
*/
static Expr *
-inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple,
- List *active_fns)
+inline_function(Oid funcid, List *args, HeapTuple func_tuple,
+ List *active_fns)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
- Oid funcid = HeapTupleGetOid(func_tuple);
Oid result_typeid = funcform->prorettype;
char result_typtype;
char *src;
@@ -1816,7 +1827,7 @@ inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple,
* stuff that parsing might create.
*/
mycxt = AllocSetContextCreate(CurrentMemoryContext,
- "inline_op_or_func",
+ "inline_function",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
@@ -1828,7 +1839,7 @@ inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple,
Anum_pg_proc_prosrc,
&isNull);
if (isNull)
- elog(ERROR, "inline_op_or_func: null prosrc for procedure %u",
+ elog(ERROR, "inline_function: null prosrc for procedure %u",
funcid);
src = DatumGetCString(DirectFunctionCall1(textout, tmp));
@@ -1877,7 +1888,7 @@ inline_op_or_func(Expr *expr, List *args, HeapTuple func_tuple,
length(querytree->targetList) != 1)
goto fail;
- newexpr = ((TargetEntry *) lfirst(querytree->targetList))->expr;
+ newexpr = (Node *) ((TargetEntry *) lfirst(querytree->targetList))->expr;
/*
* Additional validity checks on the expression. It mustn't return a
@@ -2065,17 +2076,17 @@ substitute_actual_parameters_mutator(Node *node,
* FromExpr, JoinExpr, and SetOperationStmt nodes are handled, so that query
* jointrees and setOperation trees can be processed without additional code.
*
- * expression_tree_walker will handle SubLink and SubPlan nodes by recursing
- * normally into the "lefthand" arguments (which belong to the outer plan).
- * It will also call the walker on the sub-Query node; however, when
- * expression_tree_walker itself is called on a Query node, it does nothing
- * and returns "false". The net effect is that unless the walker does
- * something special at a Query node, sub-selects will not be visited
- * during an expression tree walk. This is exactly the behavior wanted
- * in many cases --- and for those walkers that do want to recurse into
- * sub-selects, special behavior is typically needed anyway at the entry
- * to a sub-select (such as incrementing a depth counter). A walker that
- * wants to examine sub-selects should include code along the lines of:
+ * expression_tree_walker will handle SubLink and SubPlanExpr nodes by
+ * recursing normally into the "lefthand" arguments (which are expressions
+ * belonging to the outer plan). It will also call the walker on the
+ * sub-Query node; however, when expression_tree_walker itself is called on a
+ * Query node, it does nothing and returns "false". The net effect is that
+ * unless the walker does something special at a Query node, sub-selects will
+ * not be visited during an expression tree walk. This is exactly the behavior
+ * wanted in many cases --- and for those walkers that do want to recurse into
+ * sub-selects, special behavior is typically needed anyway at the entry to a
+ * sub-select (such as incrementing a depth counter). A walker that wants to
+ * examine sub-selects should include code along the lines of:
*
* if (IsA(node, Query))
* {
@@ -2115,29 +2126,12 @@ expression_tree_walker(Node *node,
return false;
switch (nodeTag(node))
{
- case T_Const:
case T_Var:
+ case T_Const:
case T_Param:
case T_RangeTblRef:
/* primitive node types with no subnodes */
break;
- case T_Expr:
- {
- Expr *expr = (Expr *) node;
-
- if (expr->opType == SUBPLAN_EXPR)
- {
- /* recurse to the SubLink node (skipping SubPlan!) */
- if (walker((Node *) ((SubPlan *) expr->oper)->sublink,
- context))
- return true;
- }
- /* for all Expr node types, examine args list */
- if (expression_tree_walker((Node *) expr->args,
- walker, context))
- return true;
- }
- break;
case T_Aggref:
return walker(((Aggref *) node)->target, context);
case T_ArrayRef:
@@ -2158,41 +2152,41 @@ expression_tree_walker(Node *node,
return true;
}
break;
- case T_FieldSelect:
- return walker(((FieldSelect *) node)->arg, context);
- case T_RelabelType:
- return walker(((RelabelType *) node)->arg, context);
- case T_CaseExpr:
+ case T_FuncExpr:
{
- CaseExpr *caseexpr = (CaseExpr *) node;
+ FuncExpr *expr = (FuncExpr *) node;
- /* we assume walker doesn't care about CaseWhens, either */
- foreach(temp, caseexpr->args)
- {
- CaseWhen *when = (CaseWhen *) lfirst(temp);
+ if (expression_tree_walker((Node *) expr->args,
+ walker, context))
+ return true;
+ }
+ break;
+ case T_OpExpr:
+ {
+ OpExpr *expr = (OpExpr *) node;
- Assert(IsA(when, CaseWhen));
- if (walker(when->expr, context))
- return true;
- if (walker(when->result, context))
- return true;
- }
- /* caseexpr->arg should be null, but we'll check it anyway */
- if (walker(caseexpr->arg, context))
+ if (expression_tree_walker((Node *) expr->args,
+ walker, context))
return true;
- if (walker(caseexpr->defresult, context))
+ }
+ break;
+ case T_DistinctExpr:
+ {
+ DistinctExpr *expr = (DistinctExpr *) node;
+
+ if (expression_tree_walker((Node *) expr->args,
+ walker, context))
return true;
}
break;
- case T_NullTest:
- return walker(((NullTest *) node)->arg, context);
- case T_BooleanTest:
- return walker(((BooleanTest *) node)->arg, context);
- case T_ConstraintTest:
- if (walker(((ConstraintTest *) node)->arg, context))
- return true;
- return walker(((ConstraintTest *) node)->check_expr, context);
- case T_ConstraintTestValue:
+ case T_BoolExpr:
+ {
+ BoolExpr *expr = (BoolExpr *) node;
+
+ if (expression_tree_walker((Node *) expr->args,
+ walker, context))
+ return true;
+ }
break;
case T_SubLink:
{
@@ -2202,7 +2196,7 @@ expression_tree_walker(Node *node,
* If the SubLink has already been processed by
* subselect.c, it will have lefthand=NIL, and we need to
* scan the oper list. Otherwise we only need to look at
- * the lefthand list (the incomplete Oper nodes in the
+ * the lefthand list (the incomplete OpExpr nodes in the
* oper list are deemed uninteresting, perhaps even
* confusing).
*/
@@ -2224,6 +2218,57 @@ expression_tree_walker(Node *node,
return walker(sublink->subselect, context);
}
break;
+ case T_SubPlanExpr:
+ {
+ SubPlanExpr *expr = (SubPlanExpr *) node;
+
+ /* recurse to the SubLink node, but not into the Plan */
+ if (walker((Node *) expr->sublink, context))
+ return true;
+ /* also examine args list */
+ if (expression_tree_walker((Node *) expr->args,
+ walker, context))
+ return true;
+ }
+ break;
+ case T_FieldSelect:
+ return walker(((FieldSelect *) node)->arg, context);
+ case T_RelabelType:
+ return walker(((RelabelType *) node)->arg, context);
+ case T_CaseExpr:
+ {
+ CaseExpr *caseexpr = (CaseExpr *) node;
+
+ /* we assume walker doesn't care about CaseWhens, either */
+ foreach(temp, caseexpr->args)
+ {
+ CaseWhen *when = (CaseWhen *) lfirst(temp);
+
+ Assert(IsA(when, CaseWhen));
+ if (walker(when->expr, context))
+ return true;
+ if (walker(when->result, context))
+ return true;
+ }
+ /* caseexpr->arg should be null, but we'll check it anyway */
+ if (walker(caseexpr->arg, context))
+ return true;
+ if (walker(caseexpr->defresult, context))
+ return true;
+ }
+ break;
+ case T_NullTest:
+ return walker(((NullTest *) node)->arg, context);
+ case T_BooleanTest:
+ return walker(((BooleanTest *) node)->arg, context);
+ case T_ConstraintTest:
+ if (walker(((ConstraintTest *) node)->arg, context))
+ return true;
+ return walker(((ConstraintTest *) node)->check_expr, context);
+ case T_ConstraintTestValue:
+ break;
+ case T_TargetEntry:
+ return walker(((TargetEntry *) node)->expr, context);
case T_Query:
/* Do nothing with a sub-Query, per discussion above */
break;
@@ -2234,8 +2279,6 @@ expression_tree_walker(Node *node,
return true;
}
break;
- case T_TargetEntry:
- return walker(((TargetEntry *) node)->expr, context);
case T_FromExpr:
{
FromExpr *from = (FromExpr *) node;
@@ -2387,14 +2430,14 @@ query_tree_walker(Query *query,
* expression_tree_mutator include all those normally found in target lists
* and qualifier clauses during the planning stage.
*
- * expression_tree_mutator will handle a SUBPLAN_EXPR node by recursing into
- * the args and slink->oper lists (which belong to the outer plan), but it
+ * expression_tree_mutator will handle a SubPlanExpr node by recursing into
+ * the args and sublink->oper lists (which belong to the outer plan), but it
* will simply copy the link to the inner plan, since that's typically what
* expression tree mutators want. A mutator that wants to modify the subplan
* can force appropriate behavior by recognizing subplan expression nodes
* and doing the right thing.
*
- * Bare SubLink nodes (without a SUBPLAN_EXPR) are handled by recursing into
+ * Bare SubLink nodes (without a SubPlanExpr) are handled by recursing into
* the "lefthand" argument list only. (A bare SubLink should be seen only if
* the tree has not yet been processed by subselect.c.) Again, this can be
* overridden by the mutator, but it seems to be the most useful default
@@ -2428,61 +2471,19 @@ expression_tree_mutator(Node *node,
return NULL;
switch (nodeTag(node))
{
- case T_Const:
case T_Var:
+ case T_Const:
case T_Param:
case T_RangeTblRef:
/* primitive node types with no subnodes */
return (Node *) copyObject(node);
- case T_Expr:
- {
- Expr *expr = (Expr *) node;
- Expr *newnode;
-
- FLATCOPY(newnode, expr, Expr);
-
- if (expr->opType == SUBPLAN_EXPR)
- {
- SubLink *oldsublink = ((SubPlan *) expr->oper)->sublink;
- SubPlan *newsubplan;
-
- /* flat-copy the oper node, which is a SubPlan */
- CHECKFLATCOPY(newsubplan, expr->oper, SubPlan);
- newnode->oper = (Node *) newsubplan;
- /* likewise its SubLink node */
- CHECKFLATCOPY(newsubplan->sublink, oldsublink, SubLink);
-
- /*
- * transform args list (params to be passed to
- * subplan)
- */
- MUTATE(newnode->args, expr->args, List *);
- /* transform sublink's oper list as well */
- MUTATE(newsubplan->sublink->oper, oldsublink->oper, List *);
-
- /*
- * but not the subplan itself, which is referenced
- * as-is
- */
- }
- else
- {
- /*
- * for other Expr node types, just transform args
- * list, linking to original oper node (OK?)
- */
- MUTATE(newnode->args, expr->args, List *);
- }
- return (Node *) newnode;
- }
- break;
case T_Aggref:
{
Aggref *aggref = (Aggref *) node;
Aggref *newnode;
FLATCOPY(newnode, aggref, Aggref);
- MUTATE(newnode->target, aggref->target, Node *);
+ MUTATE(newnode->target, aggref->target, Expr *);
return (Node *) newnode;
}
break;
@@ -2497,9 +2498,81 @@ expression_tree_mutator(Node *node,
MUTATE(newnode->reflowerindexpr, arrayref->reflowerindexpr,
List *);
MUTATE(newnode->refexpr, arrayref->refexpr,
- Node *);
+ Expr *);
MUTATE(newnode->refassgnexpr, arrayref->refassgnexpr,
- Node *);
+ Expr *);
+ return (Node *) newnode;
+ }
+ break;
+ case T_FuncExpr:
+ {
+ FuncExpr *expr = (FuncExpr *) node;
+ FuncExpr *newnode;
+
+ FLATCOPY(newnode, expr, FuncExpr);
+ MUTATE(newnode->args, expr->args, List *);
+ return (Node *) newnode;
+ }
+ break;
+ case T_OpExpr:
+ {
+ OpExpr *expr = (OpExpr *) node;
+ OpExpr *newnode;
+
+ FLATCOPY(newnode, expr, OpExpr);
+ MUTATE(newnode->args, expr->args, List *);
+ return (Node *) newnode;
+ }
+ break;
+ case T_DistinctExpr:
+ {
+ DistinctExpr *expr = (DistinctExpr *) node;
+ DistinctExpr *newnode;
+
+ FLATCOPY(newnode, expr, DistinctExpr);
+ MUTATE(newnode->args, expr->args, List *);
+ return (Node *) newnode;
+ }
+ break;
+ case T_BoolExpr:
+ {
+ BoolExpr *expr = (BoolExpr *) node;
+ BoolExpr *newnode;
+
+ FLATCOPY(newnode, expr, BoolExpr);
+ MUTATE(newnode->args, expr->args, List *);
+ return (Node *) newnode;
+ }
+ break;
+ case T_SubLink:
+ {
+ /*
+ * A "bare" SubLink (note we will not come here if we
+ * found a SubPlanExpr node above it). Transform the
+ * lefthand side, but not the oper list nor the subquery.
+ */
+ SubLink *sublink = (SubLink *) node;
+ SubLink *newnode;
+
+ FLATCOPY(newnode, sublink, SubLink);
+ MUTATE(newnode->lefthand, sublink->lefthand, List *);
+ return (Node *) newnode;
+ }
+ break;
+ case T_SubPlanExpr:
+ {
+ SubPlanExpr *expr = (SubPlanExpr *) node;
+ SubLink *oldsublink = expr->sublink;
+ SubPlanExpr *newnode;
+
+ FLATCOPY(newnode, expr, SubPlanExpr);
+ /* flat-copy the SubLink node */
+ CHECKFLATCOPY(newnode->sublink, oldsublink, SubLink);
+ /* transform args list (params to be passed to subplan) */
+ MUTATE(newnode->args, expr->args, List *);
+ /* transform sublink's oper list as well */
+ MUTATE(newnode->sublink->oper, oldsublink->oper, List *);
+ /* but not the subplan itself, which is referenced as-is */
return (Node *) newnode;
}
break;
@@ -2509,7 +2582,7 @@ expression_tree_mutator(Node *node,
FieldSelect *newnode;
FLATCOPY(newnode, fselect, FieldSelect);
- MUTATE(newnode->arg, fselect->arg, Node *);
+ MUTATE(newnode->arg, fselect->arg, Expr *);
return (Node *) newnode;
}
break;
@@ -2519,7 +2592,7 @@ expression_tree_mutator(Node *node,
RelabelType *newnode;
FLATCOPY(newnode, relabel, RelabelType);
- MUTATE(newnode->arg, relabel->arg, Node *);
+ MUTATE(newnode->arg, relabel->arg, Expr *);
return (Node *) newnode;
}
break;
@@ -2531,8 +2604,8 @@ expression_tree_mutator(Node *node,
FLATCOPY(newnode, caseexpr, CaseExpr);
MUTATE(newnode->args, caseexpr->args, List *);
/* caseexpr->arg should be null, but we'll check it anyway */
- MUTATE(newnode->arg, caseexpr->arg, Node *);
- MUTATE(newnode->defresult, caseexpr->defresult, Node *);
+ MUTATE(newnode->arg, caseexpr->arg, Expr *);
+ MUTATE(newnode->defresult, caseexpr->defresult, Expr *);
return (Node *) newnode;
}
break;
@@ -2542,8 +2615,8 @@ expression_tree_mutator(Node *node,
CaseWhen *newnode;
FLATCOPY(newnode, casewhen, CaseWhen);
- MUTATE(newnode->expr, casewhen->expr, Node *);
- MUTATE(newnode->result, casewhen->result, Node *);
+ MUTATE(newnode->expr, casewhen->expr, Expr *);
+ MUTATE(newnode->result, casewhen->result, Expr *);
return (Node *) newnode;
}
break;
@@ -2553,7 +2626,7 @@ expression_tree_mutator(Node *node,
NullTest *newnode;
FLATCOPY(newnode, ntest, NullTest);
- MUTATE(newnode->arg, ntest->arg, Node *);
+ MUTATE(newnode->arg, ntest->arg, Expr *);
return (Node *) newnode;
}
break;
@@ -2563,7 +2636,7 @@ expression_tree_mutator(Node *node,
BooleanTest *newnode;
FLATCOPY(newnode, btest, BooleanTest);
- MUTATE(newnode->arg, btest->arg, Node *);
+ MUTATE(newnode->arg, btest->arg, Expr *);
return (Node *) newnode;
}
break;
@@ -2573,8 +2646,8 @@ expression_tree_mutator(Node *node,
ConstraintTest *newnode;
FLATCOPY(newnode, ctest, ConstraintTest);
- MUTATE(newnode->arg, ctest->arg, Node *);
- MUTATE(newnode->check_expr, ctest->check_expr, Node *);
+ MUTATE(newnode->arg, ctest->arg, Expr *);
+ MUTATE(newnode->check_expr, ctest->check_expr, Expr *);
return (Node *) newnode;
}
break;
@@ -2587,18 +2660,17 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
- case T_SubLink:
+ case T_TargetEntry:
{
/*
- * A "bare" SubLink (note we will not come here if we
- * found a SUBPLAN_EXPR node above it). Transform the
- * lefthand side, but not the oper list nor the subquery.
+ * We mutate the expression, but not the resdom, by
+ * default.
*/
- SubLink *sublink = (SubLink *) node;
- SubLink *newnode;
+ TargetEntry *targetentry = (TargetEntry *) node;
+ TargetEntry *newnode;
- FLATCOPY(newnode, sublink, SubLink);
- MUTATE(newnode->lefthand, sublink->lefthand, List *);
+ FLATCOPY(newnode, targetentry, TargetEntry);
+ MUTATE(newnode->expr, targetentry->expr, Expr *);
return (Node *) newnode;
}
break;
@@ -2622,20 +2694,6 @@ expression_tree_mutator(Node *node,
return (Node *) resultlist;
}
break;
- case T_TargetEntry:
- {
- /*
- * We mutate the expression, but not the resdom, by
- * default.
- */
- TargetEntry *targetentry = (TargetEntry *) node;
- TargetEntry *newnode;
-
- FLATCOPY(newnode, targetentry, TargetEntry);
- MUTATE(newnode->expr, targetentry->expr, Node *);
- return (Node *) newnode;
- }
- break;
case T_FromExpr:
{
FromExpr *from = (FromExpr *) node;