0001-Replace-a-long-chain-of-if-s-in-eval_const_expressio.patch
text/x-patch
Filename: 0001-Replace-a-long-chain-of-if-s-in-eval_const_expressio.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0001
Subject: Replace a long chain of if's in eval_const_expressions_mutator by a switch()
| File | + | − |
|---|---|---|
| src/backend/optimizer/util/clauses.c | 869 | 864 |
From e114e3a2708cab8efd64281d09cecbd6303aa329 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Fri, 11 Nov 2011 23:32:02 +0100
Subject: [PATCH] Replace a long chain of if's in
eval_const_expressions_mutator by a switch()
For unknown reasons the function used non chained ifs for every handled
nodeType.
Replacing the if chain with if; else if; ... resulted in a small
speedup. Replacing it with a switch() in a bigger one.
When testing with a statement containing a longer VALUES statement:
pgbench -M prepared -f stmt -T 10:
orig: 10015.287829
if: 10075.482117
switch: 10246.527402
---
src/backend/optimizer/util/clauses.c | 1733 +++++++++++++++++-----------------
1 files changed, 869 insertions(+), 864 deletions(-)
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 197d9c2..f6f0b11 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -2106,233 +2106,137 @@ eval_const_expressions_mutator(Node *node,
{
if (node == NULL)
return NULL;
- if (IsA(node, Param))
+ switch(nodeTag(node))
{
- Param *param = (Param *) node;
-
- /* Look to see if we've been given a value for this Param */
- if (param->paramkind == PARAM_EXTERN &&
- context->boundParams != NULL &&
- param->paramid > 0 &&
- param->paramid <= context->boundParams->numParams)
+ case T_Param:
{
- ParamExternData *prm = &context->boundParams->params[param->paramid - 1];
+ Param *param = (Param *) node;
- if (OidIsValid(prm->ptype))
+ /* Look to see if we've been given a value for this Param */
+ if (param->paramkind == PARAM_EXTERN &&
+ context->boundParams != NULL &&
+ param->paramid > 0 &&
+ param->paramid <= context->boundParams->numParams)
{
- /* OK to substitute parameter value? */
- if (context->estimate || (prm->pflags & PARAM_FLAG_CONST))
+ ParamExternData *prm = &context->boundParams->params[param->paramid - 1];
+
+ if (OidIsValid(prm->ptype))
{
- /*
- * Return a Const representing the param value. Must copy
- * pass-by-ref datatypes, since the Param might be in a
- * memory context shorter-lived than our output plan
- * should be.
- */
- int16 typLen;
- bool typByVal;
- Datum pval;
-
- Assert(prm->ptype == param->paramtype);
- get_typlenbyval(param->paramtype, &typLen, &typByVal);
- if (prm->isnull || typByVal)
- pval = prm->value;
- else
- pval = datumCopy(prm->value, typByVal, typLen);
- return (Node *) makeConst(param->paramtype,
- param->paramtypmod,
- param->paramcollid,
- (int) typLen,
- pval,
- prm->isnull,
- typByVal);
+ /* OK to substitute parameter value? */
+ if (context->estimate || (prm->pflags & PARAM_FLAG_CONST))
+ {
+ /*
+ * Return a Const representing the param value. Must copy
+ * pass-by-ref datatypes, since the Param might be in a
+ * memory context shorter-lived than our output plan
+ * should be.
+ */
+ int16 typLen;
+ bool typByVal;
+ Datum pval;
+
+ Assert(prm->ptype == param->paramtype);
+ get_typlenbyval(param->paramtype, &typLen, &typByVal);
+ if (prm->isnull || typByVal)
+ pval = prm->value;
+ else
+ pval = datumCopy(prm->value, typByVal, typLen);
+ return (Node *) makeConst(param->paramtype,
+ param->paramtypmod,
+ param->paramcollid,
+ (int) typLen,
+ pval,
+ prm->isnull,
+ typByVal);
+ }
}
}
+ /* Not replaceable, so just copy the Param (no need to recurse) */
+ return (Node *) copyObject(param);
}
- /* Not replaceable, so just copy the Param (no need to recurse) */
- return (Node *) copyObject(param);
- }
- if (IsA(node, FuncExpr))
- {
- FuncExpr *expr = (FuncExpr *) node;
- List *args;
- bool has_named_args;
- Expr *simple;
- FuncExpr *newexpr;
- ListCell *lc;
-
- /*
- * Reduce constants in the FuncExpr's arguments, and check to see if
- * there are any named args.
- */
- args = NIL;
- has_named_args = false;
- foreach(lc, expr->args)
+ case T_FuncExpr:
{
- Node *arg = (Node *) lfirst(lc);
-
- arg = eval_const_expressions_mutator(arg, context);
- if (IsA(arg, NamedArgExpr))
- has_named_args = true;
- args = lappend(args, arg);
- }
+ FuncExpr *expr = (FuncExpr *) node;
+ List *args;
+ bool has_named_args;
+ Expr *simple;
+ FuncExpr *newexpr;
+ ListCell *lc;
- /*
- * Code for op/func reduction is pretty bulky, so split it out as a
- * separate function. Note: exprTypmod normally returns -1 for a
- * FuncExpr, but not when the node is recognizably a length coercion;
- * we want to preserve the typmod in the eventual Const if so.
- */
- simple = simplify_function((Expr *) expr,
- expr->funcid,
- expr->funcresulttype, exprTypmod(node),
- expr->funccollid,
- expr->inputcollid,
- &args,
- has_named_args, true, context);
- 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. Note that we have also converted the argument list to
- * positional notation.
- */
- newexpr = makeNode(FuncExpr);
- newexpr->funcid = expr->funcid;
- newexpr->funcresulttype = expr->funcresulttype;
- newexpr->funcretset = expr->funcretset;
- newexpr->funcformat = expr->funcformat;
- newexpr->funccollid = expr->funccollid;
- newexpr->inputcollid = expr->inputcollid;
- newexpr->args = args;
- newexpr->location = expr->location;
- return (Node *) newexpr;
- }
- if (IsA(node, OpExpr))
- {
- OpExpr *expr = (OpExpr *) node;
- List *args;
- Expr *simple;
- OpExpr *newexpr;
-
- /*
- * 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 *) context);
-
- /*
- * Need to get OID of underlying function. Okay to scribble on input
- * to this extent.
- */
- set_opfuncid(expr);
+ /*
+ * Reduce constants in the FuncExpr's arguments, and check to see if
+ * there are any named args.
+ */
+ args = NIL;
+ has_named_args = false;
+ foreach(lc, expr->args)
+ {
+ Node *arg = (Node *) lfirst(lc);
- /*
- * Code for op/func reduction is pretty bulky, so split it out as a
- * separate function.
- */
- simple = simplify_function((Expr *) expr,
- expr->opfuncid,
- expr->opresulttype, -1,
- expr->opcollid,
- expr->inputcollid,
- &args,
- false, true, context);
- if (simple) /* successfully simplified it */
- return (Node *) simple;
+ arg = eval_const_expressions_mutator(arg, context);
+ if (IsA(arg, NamedArgExpr))
+ has_named_args = true;
+ args = lappend(args, arg);
+ }
- /*
- * If the operator is boolean equality or inequality, we know how to
- * simplify cases involving one constant and one non-constant
- * argument.
- */
- if (expr->opno == BooleanEqualOperator ||
- expr->opno == BooleanNotEqualOperator)
- {
- simple = (Expr *) simplify_boolean_equality(expr->opno, args);
- if (simple) /* successfully simplified it */
+ /*
+ * Code for op/func reduction is pretty bulky, so split it out as a
+ * separate function. Note: exprTypmod normally returns -1 for a
+ * FuncExpr, but not when the node is recognizably a length coercion;
+ * we want to preserve the typmod in the eventual Const if so.
+ */
+ simple = simplify_function((Expr *) expr,
+ expr->funcid,
+ expr->funcresulttype, exprTypmod(node),
+ expr->funccollid,
+ expr->inputcollid,
+ &args,
+ has_named_args, true, context);
+ 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->opcollid = expr->opcollid;
- newexpr->inputcollid = expr->inputcollid;
- newexpr->args = args;
- newexpr->location = expr->location;
- return (Node *) newexpr;
- }
- if (IsA(node, DistinctExpr))
- {
- DistinctExpr *expr = (DistinctExpr *) node;
- List *args;
- ListCell *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.
- */
- args = (List *) expression_tree_mutator((Node *) expr->args,
- eval_const_expressions_mutator,
- (void *) context);
- /*
- * We must do our own check for NULLs because DistinctExpr 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;
+ /*
+ * The expression cannot be simplified any further, so build and
+ * return a replacement FuncExpr node using the possibly-simplified
+ * arguments. Note that we have also converted the argument list to
+ * positional notation.
+ */
+ newexpr = makeNode(FuncExpr);
+ newexpr->funcid = expr->funcid;
+ newexpr->funcresulttype = expr->funcresulttype;
+ newexpr->funcretset = expr->funcretset;
+ newexpr->funcformat = expr->funcformat;
+ newexpr->funccollid = expr->funccollid;
+ newexpr->inputcollid = expr->inputcollid;
+ newexpr->args = args;
+ newexpr->location = expr->location;
+ return (Node *) newexpr;
}
-
- /* all constants? then can optimize this out */
- if (!has_nonconst_input)
+ case T_OpExpr:
{
- /* all nulls? then not distinct */
- if (all_null_input)
- return makeBoolConst(false, false);
+ OpExpr *expr = (OpExpr *) node;
+ List *args;
+ Expr *simple;
+ OpExpr *newexpr;
- /* 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!) */
+ /*
+ * 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 *) context);
/*
- * Need to get OID of underlying function. Okay to scribble on
- * input to this extent.
+ * Need to get OID of underlying function. Okay to scribble on input
+ * to this extent.
*/
- set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
+ set_opfuncid(expr);
/*
- * Code for op/func reduction is pretty bulky, so split it out as
- * a separate function.
+ * Code for op/func reduction is pretty bulky, so split it out as a
+ * separate function.
*/
simple = simplify_function((Expr *) expr,
expr->opfuncid,
@@ -2340,755 +2244,856 @@ eval_const_expressions_mutator(Node *node,
expr->opcollid,
expr->inputcollid,
&args,
- false, false, context);
- if (simple) /* successfully simplified it */
- {
- /*
- * Since the underlying operator is "=", must negate its
- * result
- */
- Const *csimple = (Const *) simple;
+ false, true, context);
+ if (simple) /* successfully simplified it */
+ return (Node *) simple;
- Assert(IsA(csimple, Const));
- csimple->constvalue =
- BoolGetDatum(!DatumGetBool(csimple->constvalue));
- return (Node *) csimple;
+ /*
+ * If the operator is boolean equality or inequality, we know how to
+ * simplify cases involving one constant and one non-constant
+ * argument.
+ */
+ if (expr->opno == BooleanEqualOperator ||
+ expr->opno == BooleanNotEqualOperator)
+ {
+ simple = (Expr *) simplify_boolean_equality(expr->opno, args);
+ 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->opcollid = expr->opcollid;
+ newexpr->inputcollid = expr->inputcollid;
+ newexpr->args = args;
+ newexpr->location = expr->location;
+ return (Node *) newexpr;
}
+ case T_DistinctExpr:
+ {
+ DistinctExpr *expr = (DistinctExpr *) node;
+ List *args;
+ ListCell *arg;
+ bool has_null_input = false;
+ bool all_null_input = true;
+ bool has_nonconst_input = false;
+ Expr *simple;
+ DistinctExpr *newexpr;
- /*
- * 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->opcollid = expr->opcollid;
- newexpr->inputcollid = expr->inputcollid;
- newexpr->args = args;
- newexpr->location = expr->location;
- return (Node *) newexpr;
- }
- if (IsA(node, BoolExpr))
- {
- BoolExpr *expr = (BoolExpr *) node;
+ /*
+ * 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.
+ */
+ args = (List *) expression_tree_mutator((Node *) expr->args,
+ eval_const_expressions_mutator,
+ (void *) context);
- switch (expr->boolop)
- {
- case OR_EXPR:
- {
- List *newargs;
- bool haveNull = false;
- bool forceTrue = false;
-
- newargs = simplify_or_arguments(expr->args, context,
- &haveNull, &forceTrue);
- if (forceTrue)
- return makeBoolConst(true, false);
- if (haveNull)
- newargs = lappend(newargs, makeBoolConst(false, true));
- /* If all the inputs are FALSE, result is FALSE */
- if (newargs == NIL)
- return makeBoolConst(false, false);
- /* If only one nonconst-or-NULL input, it's the result */
- if (list_length(newargs) == 1)
- return (Node *) linitial(newargs);
- /* Else we still need an OR node */
- return (Node *) make_orclause(newargs);
- }
- case AND_EXPR:
+ /*
+ * We must do our own check for NULLs because DistinctExpr has
+ * different results for NULL input than the underlying operator does.
+ */
+ foreach(arg, args)
+ {
+ if (IsA(lfirst(arg), Const))
{
- List *newargs;
- bool haveNull = false;
- bool forceFalse = false;
-
- newargs = simplify_and_arguments(expr->args, context,
- &haveNull, &forceFalse);
- if (forceFalse)
- return makeBoolConst(false, false);
- if (haveNull)
- newargs = lappend(newargs, makeBoolConst(false, true));
- /* If all the inputs are TRUE, result is TRUE */
- if (newargs == NIL)
- return makeBoolConst(true, false);
- /* If only one nonconst-or-NULL input, it's the result */
- if (list_length(newargs) == 1)
- return (Node *) linitial(newargs);
- /* Else we still need an AND node */
- return (Node *) make_andclause(newargs);
+ has_null_input |= ((Const *) lfirst(arg))->constisnull;
+ all_null_input &= ((Const *) lfirst(arg))->constisnull;
}
- case NOT_EXPR:
- {
- Node *arg;
+ else
+ has_nonconst_input = true;
+ }
+
+ /* 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);
- Assert(list_length(expr->args) == 1);
- arg = eval_const_expressions_mutator(linitial(expr->args),
- context);
+ /* otherwise try to evaluate the '=' operator */
+ /* (NOT okay to try to inline it, though!) */
+ /*
+ * 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 *) expr,
+ expr->opfuncid,
+ expr->opresulttype, -1,
+ expr->opcollid,
+ expr->inputcollid,
+ &args,
+ false, false, context);
+ if (simple) /* successfully simplified it */
+ {
/*
- * Use negate_clause() to see if we can simplify away the
- * NOT.
+ * Since the underlying operator is "=", must negate its
+ * result
*/
- return negate_clause(arg);
+ Const *csimple = (Const *) simple;
+
+ Assert(IsA(csimple, Const));
+ csimple->constvalue =
+ BoolGetDatum(!DatumGetBool(csimple->constvalue));
+ return (Node *) csimple;
}
- default:
- elog(ERROR, "unrecognized boolop: %d",
- (int) expr->boolop);
- 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->opcollid = expr->opcollid;
+ newexpr->inputcollid = expr->inputcollid;
+ newexpr->args = args;
+ newexpr->location = expr->location;
+ return (Node *) newexpr;
}
- }
- if (IsA(node, SubPlan) ||
- IsA(node, AlternativeSubPlan))
- {
- /*
- * Return a SubPlan unchanged --- too late to do anything with it.
- *
- * XXX should we ereport() here instead? Probably this routine should
- * never be invoked after SubPlan creation.
- */
- return node;
- }
- if (IsA(node, RelabelType))
- {
- /*
- * If we can simplify the input to a constant, then we don't need the
- * RelabelType node anymore: just change the type field of the Const
- * node. Otherwise, must copy the RelabelType node.
- */
- RelabelType *relabel = (RelabelType *) node;
- Node *arg;
+ case T_BoolExpr:
+ {
+ BoolExpr *expr = (BoolExpr *) node;
+
+ switch (expr->boolop)
+ {
+ case OR_EXPR:
+ {
+ List *newargs;
+ bool haveNull = false;
+ bool forceTrue = false;
+
+ newargs = simplify_or_arguments(expr->args, context,
+ &haveNull, &forceTrue);
+ if (forceTrue)
+ return makeBoolConst(true, false);
+ if (haveNull)
+ newargs = lappend(newargs, makeBoolConst(false, true));
+ /* If all the inputs are FALSE, result is FALSE */
+ if (newargs == NIL)
+ return makeBoolConst(false, false);
+ /* If only one nonconst-or-NULL input, it's the result */
+ if (list_length(newargs) == 1)
+ return (Node *) linitial(newargs);
+ /* Else we still need an OR node */
+ return (Node *) make_orclause(newargs);
+ }
+ case AND_EXPR:
+ {
+ List *newargs;
+ bool haveNull = false;
+ bool forceFalse = false;
+
+ newargs = simplify_and_arguments(expr->args, context,
+ &haveNull, &forceFalse);
+ if (forceFalse)
+ return makeBoolConst(false, false);
+ if (haveNull)
+ newargs = lappend(newargs, makeBoolConst(false, true));
+ /* If all the inputs are TRUE, result is TRUE */
+ if (newargs == NIL)
+ return makeBoolConst(true, false);
+ /* If only one nonconst-or-NULL input, it's the result */
+ if (list_length(newargs) == 1)
+ return (Node *) linitial(newargs);
+ /* Else we still need an AND node */
+ return (Node *) make_andclause(newargs);
+ }
+ case NOT_EXPR:
+ {
+ Node *arg;
+
+ Assert(list_length(expr->args) == 1);
+ arg = eval_const_expressions_mutator(linitial(expr->args),
+ context);
+
+ /*
+ * Use negate_clause() to see if we can simplify away the
+ * NOT.
+ */
+ return negate_clause(arg);
+ }
+ default:
+ elog(ERROR, "unrecognized boolop: %d",
+ (int) expr->boolop);
+ break;
+ }
+ }
+ case T_SubPlan:
+ case T_AlternativeSubPlan:
+ /*
+ * Return a SubPlan unchanged --- too late to do anything with it.
+ *
+ * XXX should we ereport() here instead? Probably this routine should
+ * never be invoked after SubPlan creation.
+ */
+ return node;
+ case T_RelabelType:
+ {
+ /*
+ * If we can simplify the input to a constant, then we don't need the
+ * RelabelType node anymore: just change the type field of the Const
+ * node. Otherwise, must copy the RelabelType node.
+ */
+ RelabelType *relabel = (RelabelType *) node;
+ Node *arg;
- arg = eval_const_expressions_mutator((Node *) relabel->arg,
- context);
+ arg = eval_const_expressions_mutator((Node *) relabel->arg,
+ context);
- /*
- * If we find stacked RelabelTypes (eg, from foo :: int :: oid) we can
- * discard all but the top one.
- */
- while (arg && IsA(arg, RelabelType))
- arg = (Node *) ((RelabelType *) arg)->arg;
+ /*
+ * If we find stacked RelabelTypes (eg, from foo :: int :: oid) we can
+ * discard all but the top one.
+ */
+ while (arg && IsA(arg, RelabelType))
+ arg = (Node *) ((RelabelType *) arg)->arg;
- if (arg && IsA(arg, Const))
- {
- Const *con = (Const *) arg;
+ if (arg && IsA(arg, Const))
+ {
+ Const *con = (Const *) arg;
- con->consttype = relabel->resulttype;
- con->consttypmod = relabel->resulttypmod;
- con->constcollid = relabel->resultcollid;
- return (Node *) con;
+ con->consttype = relabel->resulttype;
+ con->consttypmod = relabel->resulttypmod;
+ con->constcollid = relabel->resultcollid;
+ return (Node *) con;
+ }
+ else
+ {
+ RelabelType *newrelabel = makeNode(RelabelType);
+
+ newrelabel->arg = (Expr *) arg;
+ newrelabel->resulttype = relabel->resulttype;
+ newrelabel->resulttypmod = relabel->resulttypmod;
+ newrelabel->resultcollid = relabel->resultcollid;
+ newrelabel->relabelformat = relabel->relabelformat;
+ newrelabel->location = relabel->location;
+ return (Node *) newrelabel;
+ }
}
- else
+ case T_CoerceViaIO:
{
- RelabelType *newrelabel = makeNode(RelabelType);
-
- newrelabel->arg = (Expr *) arg;
- newrelabel->resulttype = relabel->resulttype;
- newrelabel->resulttypmod = relabel->resulttypmod;
- newrelabel->resultcollid = relabel->resultcollid;
- newrelabel->relabelformat = relabel->relabelformat;
- newrelabel->location = relabel->location;
- return (Node *) newrelabel;
- }
- }
- if (IsA(node, CoerceViaIO))
- {
- CoerceViaIO *expr = (CoerceViaIO *) node;
- Expr *arg;
- List *args;
- Oid outfunc;
- bool outtypisvarlena;
- Oid infunc;
- Oid intypioparam;
- Expr *simple;
- CoerceViaIO *newexpr;
+ CoerceViaIO *expr = (CoerceViaIO *) node;
+ Expr *arg;
+ List *args;
+ Oid outfunc;
+ bool outtypisvarlena;
+ Oid infunc;
+ Oid intypioparam;
+ Expr *simple;
+ CoerceViaIO *newexpr;
- /*
- * Reduce constants in the CoerceViaIO's argument.
- */
- arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg,
- context);
- args = list_make1(arg);
+ /*
+ * Reduce constants in the CoerceViaIO's argument.
+ */
+ arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg,
+ context);
+ args = list_make1(arg);
- /*
- * CoerceViaIO represents calling the source type's output function
- * then the result type's input function. So, try to simplify it as
- * though it were a stack of two such function calls. First we need
- * to know what the functions are.
- *
- * Note that the coercion functions are assumed not to care about
- * input collation, so we just pass InvalidOid for that.
- */
- getTypeOutputInfo(exprType((Node *) arg), &outfunc, &outtypisvarlena);
- getTypeInputInfo(expr->resulttype, &infunc, &intypioparam);
-
- simple = simplify_function(NULL,
- outfunc,
- CSTRINGOID, -1,
- InvalidOid,
- InvalidOid,
- &args,
- false, true, context);
- if (simple) /* successfully simplified output fn */
- {
/*
- * Input functions may want 1 to 3 arguments. We always supply
- * all three, trusting that nothing downstream will complain.
+ * CoerceViaIO represents calling the source type's output function
+ * then the result type's input function. So, try to simplify it as
+ * though it were a stack of two such function calls. First we need
+ * to know what the functions are.
+ *
+ * Note that the coercion functions are assumed not to care about
+ * input collation, so we just pass InvalidOid for that.
*/
- args = list_make3(simple,
- makeConst(OIDOID, -1, InvalidOid, sizeof(Oid),
- ObjectIdGetDatum(intypioparam),
- false, true),
- makeConst(INT4OID, -1, InvalidOid, sizeof(int32),
- Int32GetDatum(-1),
- false, true));
+ getTypeOutputInfo(exprType((Node *) arg), &outfunc, &outtypisvarlena);
+ getTypeInputInfo(expr->resulttype, &infunc, &intypioparam);
simple = simplify_function(NULL,
- infunc,
- expr->resulttype, -1,
- expr->resultcollid,
+ outfunc,
+ CSTRINGOID, -1,
+ InvalidOid,
InvalidOid,
&args,
false, true, context);
- if (simple) /* successfully simplified input fn */
- return (Node *) simple;
+ if (simple) /* successfully simplified output fn */
+ {
+ /*
+ * Input functions may want 1 to 3 arguments. We always supply
+ * all three, trusting that nothing downstream will complain.
+ */
+ args = list_make3(simple,
+ makeConst(OIDOID, -1, InvalidOid, sizeof(Oid),
+ ObjectIdGetDatum(intypioparam),
+ false, true),
+ makeConst(INT4OID, -1, InvalidOid, sizeof(int32),
+ Int32GetDatum(-1),
+ false, true));
+
+ simple = simplify_function(NULL,
+ infunc,
+ expr->resulttype, -1,
+ expr->resultcollid,
+ InvalidOid,
+ &args,
+ false, true, context);
+ if (simple) /* successfully simplified input fn */
+ return (Node *) simple;
+ }
+
+ /*
+ * The expression cannot be simplified any further, so build and
+ * return a replacement CoerceViaIO node using the possibly-simplified
+ * argument.
+ */
+ newexpr = makeNode(CoerceViaIO);
+ newexpr->arg = arg;
+ newexpr->resulttype = expr->resulttype;
+ newexpr->resultcollid = expr->resultcollid;
+ newexpr->coerceformat = expr->coerceformat;
+ newexpr->location = expr->location;
+ return (Node *) newexpr;
}
+ case T_ArrayCoerceExpr:
+ {
+ ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
+ Expr *arg;
+ ArrayCoerceExpr *newexpr;
- /*
- * The expression cannot be simplified any further, so build and
- * return a replacement CoerceViaIO node using the possibly-simplified
- * argument.
- */
- newexpr = makeNode(CoerceViaIO);
- newexpr->arg = arg;
- newexpr->resulttype = expr->resulttype;
- newexpr->resultcollid = expr->resultcollid;
- newexpr->coerceformat = expr->coerceformat;
- newexpr->location = expr->location;
- return (Node *) newexpr;
- }
- if (IsA(node, ArrayCoerceExpr))
- {
- ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
- Expr *arg;
- ArrayCoerceExpr *newexpr;
+ /*
+ * Reduce constants in the ArrayCoerceExpr's argument, then build a
+ * new ArrayCoerceExpr.
+ */
+ arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg,
+ context);
+
+ newexpr = makeNode(ArrayCoerceExpr);
+ newexpr->arg = arg;
+ newexpr->elemfuncid = expr->elemfuncid;
+ newexpr->resulttype = expr->resulttype;
+ newexpr->resulttypmod = expr->resulttypmod;
+ newexpr->resultcollid = expr->resultcollid;
+ newexpr->isExplicit = expr->isExplicit;
+ newexpr->coerceformat = expr->coerceformat;
+ newexpr->location = expr->location;
- /*
- * Reduce constants in the ArrayCoerceExpr's argument, then build a
- * new ArrayCoerceExpr.
- */
- arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg,
- context);
-
- newexpr = makeNode(ArrayCoerceExpr);
- newexpr->arg = arg;
- newexpr->elemfuncid = expr->elemfuncid;
- newexpr->resulttype = expr->resulttype;
- newexpr->resulttypmod = expr->resulttypmod;
- newexpr->resultcollid = expr->resultcollid;
- newexpr->isExplicit = expr->isExplicit;
- newexpr->coerceformat = expr->coerceformat;
- newexpr->location = expr->location;
+ /*
+ * If constant argument and it's a binary-coercible or immutable
+ * conversion, we can simplify it to a constant.
+ */
+ if (arg && IsA(arg, Const) &&
+ (!OidIsValid(newexpr->elemfuncid) ||
+ func_volatile(newexpr->elemfuncid) == PROVOLATILE_IMMUTABLE))
+ return (Node *) evaluate_expr((Expr *) newexpr,
+ newexpr->resulttype,
+ newexpr->resulttypmod,
+ newexpr->resultcollid);
+
+ /* Else we must return the partially-simplified node */
+ return (Node *) newexpr;
+ }
+ case T_CollateExpr:
+ {
+ /*
+ * If we can simplify the input to a constant, then we don't need the
+ * CollateExpr node at all: just change the constcollid field of the
+ * Const node. Otherwise, replace the CollateExpr with a RelabelType.
+ * (We do that so as to improve uniformity of expression
+ * representation and thus simplify comparison of expressions.)
+ */
+ CollateExpr *collate = (CollateExpr *) node;
+ Node *arg;
- /*
- * If constant argument and it's a binary-coercible or immutable
- * conversion, we can simplify it to a constant.
- */
- if (arg && IsA(arg, Const) &&
- (!OidIsValid(newexpr->elemfuncid) ||
- func_volatile(newexpr->elemfuncid) == PROVOLATILE_IMMUTABLE))
- return (Node *) evaluate_expr((Expr *) newexpr,
- newexpr->resulttype,
- newexpr->resulttypmod,
- newexpr->resultcollid);
-
- /* Else we must return the partially-simplified node */
- return (Node *) newexpr;
- }
- if (IsA(node, CollateExpr))
- {
- /*
- * If we can simplify the input to a constant, then we don't need the
- * CollateExpr node at all: just change the constcollid field of the
- * Const node. Otherwise, replace the CollateExpr with a RelabelType.
- * (We do that so as to improve uniformity of expression
- * representation and thus simplify comparison of expressions.)
- */
- CollateExpr *collate = (CollateExpr *) node;
- Node *arg;
+ arg = eval_const_expressions_mutator((Node *) collate->arg,
+ context);
- arg = eval_const_expressions_mutator((Node *) collate->arg,
- context);
+ if (arg && IsA(arg, Const))
+ {
+ Const *con = (Const *) arg;
- if (arg && IsA(arg, Const))
- {
- Const *con = (Const *) arg;
+ con->constcollid = collate->collOid;
+ return (Node *) con;
+ }
+ else if (collate->collOid == exprCollation(arg))
+ {
+ /* Don't need a RelabelType either... */
+ return arg;
+ }
+ else
+ {
+ RelabelType *relabel = makeNode(RelabelType);
- con->constcollid = collate->collOid;
- return (Node *) con;
- }
- else if (collate->collOid == exprCollation(arg))
- {
- /* Don't need a RelabelType either... */
- return arg;
+ relabel->resulttype = exprType(arg);
+ relabel->resulttypmod = exprTypmod(arg);
+ relabel->resultcollid = collate->collOid;
+ relabel->relabelformat = COERCE_DONTCARE;
+ relabel->location = collate->location;
+
+ /* Don't create stacked RelabelTypes */
+ while (arg && IsA(arg, RelabelType))
+ arg = (Node *) ((RelabelType *) arg)->arg;
+ relabel->arg = (Expr *) arg;
+
+ return (Node *) relabel;
+ }
}
- else
+ case T_CaseExpr:
{
- RelabelType *relabel = makeNode(RelabelType);
+ /*----------
+ * CASE expressions can be simplified if there are constant
+ * condition clauses:
+ * FALSE (or NULL): drop the alternative
+ * TRUE: drop all remaining alternatives
+ * If the first non-FALSE alternative is a constant TRUE, we can
+ * simplify the entire CASE to that alternative's expression.
+ * If there are no non-FALSE alternatives, we simplify the entire
+ * CASE to the default result (ELSE result).
+ *
+ * If we have a simple-form CASE with constant test expression,
+ * we substitute the constant value for contained CaseTestExpr
+ * placeholder nodes, so that we have the opportunity to reduce
+ * constant test conditions. For example this allows
+ * CASE 0 WHEN 0 THEN 1 ELSE 1/0 END
+ * to reduce to 1 rather than drawing a divide-by-0 error. Note
+ * that when the test expression is constant, we don't have to
+ * include it in the resulting CASE; for example
+ * CASE 0 WHEN x THEN y ELSE z END
+ * is transformed by the parser to
+ * CASE 0 WHEN CaseTestExpr = x THEN y ELSE z END
+ * which we can simplify to
+ * CASE WHEN 0 = x THEN y ELSE z END
+ * It is not necessary for the executor to evaluate the "arg"
+ * expression when executing the CASE, since any contained
+ * CaseTestExprs that might have referred to it will have been
+ * replaced by the constant.
+ *----------
+ */
+ CaseExpr *caseexpr = (CaseExpr *) node;
+ CaseExpr *newcase;
+ Node *save_case_val;
+ Node *newarg;
+ List *newargs;
+ bool const_true_cond;
+ Node *defresult = NULL;
+ ListCell *arg;
+
+ /* Simplify the test expression, if any */
+ newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,
+ context);
- relabel->resulttype = exprType(arg);
- relabel->resulttypmod = exprTypmod(arg);
- relabel->resultcollid = collate->collOid;
- relabel->relabelformat = COERCE_DONTCARE;
- relabel->location = collate->location;
+ /* Set up for contained CaseTestExpr nodes */
+ save_case_val = context->case_val;
+ if (newarg && IsA(newarg, Const))
+ {
+ context->case_val = newarg;
+ newarg = NULL; /* not needed anymore, see comment above */
+ }
+ else
+ context->case_val = NULL;
- /* Don't create stacked RelabelTypes */
- while (arg && IsA(arg, RelabelType))
- arg = (Node *) ((RelabelType *) arg)->arg;
- relabel->arg = (Expr *) arg;
+ /* Simplify the WHEN clauses */
+ newargs = NIL;
+ const_true_cond = false;
+ foreach(arg, caseexpr->args)
+ {
+ CaseWhen *oldcasewhen = (CaseWhen *) lfirst(arg);
+ Node *casecond;
+ Node *caseresult;
- return (Node *) relabel;
- }
- }
- if (IsA(node, CaseExpr))
- {
- /*----------
- * CASE expressions can be simplified if there are constant
- * condition clauses:
- * FALSE (or NULL): drop the alternative
- * TRUE: drop all remaining alternatives
- * If the first non-FALSE alternative is a constant TRUE, we can
- * simplify the entire CASE to that alternative's expression.
- * If there are no non-FALSE alternatives, we simplify the entire
- * CASE to the default result (ELSE result).
- *
- * If we have a simple-form CASE with constant test expression,
- * we substitute the constant value for contained CaseTestExpr
- * placeholder nodes, so that we have the opportunity to reduce
- * constant test conditions. For example this allows
- * CASE 0 WHEN 0 THEN 1 ELSE 1/0 END
- * to reduce to 1 rather than drawing a divide-by-0 error. Note
- * that when the test expression is constant, we don't have to
- * include it in the resulting CASE; for example
- * CASE 0 WHEN x THEN y ELSE z END
- * is transformed by the parser to
- * CASE 0 WHEN CaseTestExpr = x THEN y ELSE z END
- * which we can simplify to
- * CASE WHEN 0 = x THEN y ELSE z END
- * It is not necessary for the executor to evaluate the "arg"
- * expression when executing the CASE, since any contained
- * CaseTestExprs that might have referred to it will have been
- * replaced by the constant.
- *----------
- */
- CaseExpr *caseexpr = (CaseExpr *) node;
- CaseExpr *newcase;
- Node *save_case_val;
- Node *newarg;
- List *newargs;
- bool const_true_cond;
- Node *defresult = NULL;
- ListCell *arg;
-
- /* Simplify the test expression, if any */
- newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,
- context);
-
- /* Set up for contained CaseTestExpr nodes */
- save_case_val = context->case_val;
- if (newarg && IsA(newarg, Const))
- {
- context->case_val = newarg;
- newarg = NULL; /* not needed anymore, see comment above */
- }
- else
- context->case_val = NULL;
+ Assert(IsA(oldcasewhen, CaseWhen));
- /* Simplify the WHEN clauses */
- newargs = NIL;
- const_true_cond = false;
- foreach(arg, caseexpr->args)
- {
- CaseWhen *oldcasewhen = (CaseWhen *) lfirst(arg);
- Node *casecond;
- Node *caseresult;
+ /* Simplify this alternative's test condition */
+ casecond =
+ eval_const_expressions_mutator((Node *) oldcasewhen->expr,
+ context);
- Assert(IsA(oldcasewhen, CaseWhen));
+ /*
+ * If the test condition is constant FALSE (or NULL), then drop
+ * this WHEN clause completely, without processing the result.
+ */
+ if (casecond && IsA(casecond, Const))
+ {
+ Const *const_input = (Const *) casecond;
- /* Simplify this alternative's test condition */
- casecond =
- eval_const_expressions_mutator((Node *) oldcasewhen->expr,
- context);
+ if (const_input->constisnull ||
+ !DatumGetBool(const_input->constvalue))
+ continue; /* drop alternative with FALSE condition */
+ /* Else it's constant TRUE */
+ const_true_cond = true;
+ }
- /*
- * If the test condition is constant FALSE (or NULL), then drop
- * this WHEN clause completely, without processing the result.
- */
- if (casecond && IsA(casecond, Const))
- {
- Const *const_input = (Const *) casecond;
+ /* Simplify this alternative's result value */
+ caseresult =
+ eval_const_expressions_mutator((Node *) oldcasewhen->result,
+ context);
- if (const_input->constisnull ||
- !DatumGetBool(const_input->constvalue))
- continue; /* drop alternative with FALSE condition */
- /* Else it's constant TRUE */
- const_true_cond = true;
- }
+ /* If non-constant test condition, emit a new WHEN node */
+ if (!const_true_cond)
+ {
+ CaseWhen *newcasewhen = makeNode(CaseWhen);
- /* Simplify this alternative's result value */
- caseresult =
- eval_const_expressions_mutator((Node *) oldcasewhen->result,
- context);
+ newcasewhen->expr = (Expr *) casecond;
+ newcasewhen->result = (Expr *) caseresult;
+ newcasewhen->location = oldcasewhen->location;
+ newargs = lappend(newargs, newcasewhen);
+ continue;
+ }
- /* If non-constant test condition, emit a new WHEN node */
+ /*
+ * Found a TRUE condition, so none of the remaining alternatives
+ * can be reached. We treat the result as the default result.
+ */
+ defresult = caseresult;
+ break;
+ }
+
+ /* Simplify the default result, unless we replaced it above */
if (!const_true_cond)
- {
- CaseWhen *newcasewhen = makeNode(CaseWhen);
+ defresult =
+ eval_const_expressions_mutator((Node *) caseexpr->defresult,
+ context);
- newcasewhen->expr = (Expr *) casecond;
- newcasewhen->result = (Expr *) caseresult;
- newcasewhen->location = oldcasewhen->location;
- newargs = lappend(newargs, newcasewhen);
- continue;
- }
+ context->case_val = save_case_val;
+ /* If no non-FALSE alternatives, CASE reduces to the default result */
+ if (newargs == NIL)
+ return defresult;
+ /* Otherwise we need a new CASE node */
+ newcase = makeNode(CaseExpr);
+ newcase->casetype = caseexpr->casetype;
+ newcase->casecollid = caseexpr->casecollid;
+ newcase->arg = (Expr *) newarg;
+ newcase->args = newargs;
+ newcase->defresult = (Expr *) defresult;
+ newcase->location = caseexpr->location;
+ return (Node *) newcase;
+ }
+ case T_CaseTestExpr:
+ {
/*
- * Found a TRUE condition, so none of the remaining alternatives
- * can be reached. We treat the result as the default result.
+ * If we know a constant test value for the current CASE construct,
+ * substitute it for the placeholder. Else just return the
+ * placeholder as-is.
*/
- defresult = caseresult;
- break;
+ if (context->case_val)
+ return copyObject(context->case_val);
+ else
+ return copyObject(node);
}
-
- /* Simplify the default result, unless we replaced it above */
- if (!const_true_cond)
- defresult =
- eval_const_expressions_mutator((Node *) caseexpr->defresult,
- context);
-
- context->case_val = save_case_val;
-
- /* If no non-FALSE alternatives, CASE reduces to the default result */
- if (newargs == NIL)
- return defresult;
- /* Otherwise we need a new CASE node */
- newcase = makeNode(CaseExpr);
- newcase->casetype = caseexpr->casetype;
- newcase->casecollid = caseexpr->casecollid;
- newcase->arg = (Expr *) newarg;
- newcase->args = newargs;
- newcase->defresult = (Expr *) defresult;
- newcase->location = caseexpr->location;
- return (Node *) newcase;
- }
- if (IsA(node, CaseTestExpr))
- {
- /*
- * If we know a constant test value for the current CASE construct,
- * substitute it for the placeholder. Else just return the
- * placeholder as-is.
- */
- if (context->case_val)
- return copyObject(context->case_val);
- else
- return copyObject(node);
- }
- if (IsA(node, ArrayExpr))
- {
- ArrayExpr *arrayexpr = (ArrayExpr *) node;
- ArrayExpr *newarray;
- bool all_const = true;
- List *newelems;
- ListCell *element;
-
- newelems = NIL;
- foreach(element, arrayexpr->elements)
+ case T_ArrayExpr:
{
- Node *e;
-
- e = eval_const_expressions_mutator((Node *) lfirst(element),
- context);
- if (!IsA(e, Const))
- all_const = false;
- newelems = lappend(newelems, e);
- }
+ ArrayExpr *arrayexpr = (ArrayExpr *) node;
+ ArrayExpr *newarray;
+ bool all_const = true;
+ List *newelems;
+ ListCell *element;
+
+ newelems = NIL;
+ foreach(element, arrayexpr->elements)
+ {
+ Node *e;
- newarray = makeNode(ArrayExpr);
- newarray->array_typeid = arrayexpr->array_typeid;
- newarray->array_collid = arrayexpr->array_collid;
- newarray->element_typeid = arrayexpr->element_typeid;
- newarray->elements = newelems;
- newarray->multidims = arrayexpr->multidims;
- newarray->location = arrayexpr->location;
-
- if (all_const)
- return (Node *) evaluate_expr((Expr *) newarray,
- newarray->array_typeid,
- exprTypmod(node),
- newarray->array_collid);
-
- return (Node *) newarray;
- }
- if (IsA(node, CoalesceExpr))
- {
- CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
- CoalesceExpr *newcoalesce;
- List *newargs;
- ListCell *arg;
+ e = eval_const_expressions_mutator((Node *) lfirst(element),
+ context);
+ if (!IsA(e, Const))
+ all_const = false;
+ newelems = lappend(newelems, e);
+ }
- newargs = NIL;
- foreach(arg, coalesceexpr->args)
+ newarray = makeNode(ArrayExpr);
+ newarray->array_typeid = arrayexpr->array_typeid;
+ newarray->array_collid = arrayexpr->array_collid;
+ newarray->element_typeid = arrayexpr->element_typeid;
+ newarray->elements = newelems;
+ newarray->multidims = arrayexpr->multidims;
+ newarray->location = arrayexpr->location;
+
+ if (all_const)
+ return (Node *) evaluate_expr((Expr *) newarray,
+ newarray->array_typeid,
+ exprTypmod(node),
+ newarray->array_collid);
+
+ return (Node *) newarray;
+ }
+ case T_CoalesceExpr:
{
- Node *e;
-
- e = eval_const_expressions_mutator((Node *) lfirst(arg),
- context);
+ CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
+ CoalesceExpr *newcoalesce;
+ List *newargs;
+ ListCell *arg;
- /*
- * 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 it is the result. Otherwise,
- * it's the next argument, but we can drop following arguments
- * since they will never be reached.
- */
- if (IsA(e, Const))
+ newargs = NIL;
+ foreach(arg, coalesceexpr->args)
{
- if (((Const *) e)->constisnull)
- continue; /* drop null constant */
- if (newargs == NIL)
- return e; /* first expr */
+ Node *e;
+
+ e = eval_const_expressions_mutator((Node *) lfirst(arg),
+ context);
+
+ /*
+ * 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 it is the result. Otherwise,
+ * it's the next argument, but we can drop following arguments
+ * since they will never be reached.
+ */
+ if (IsA(e, Const))
+ {
+ if (((Const *) e)->constisnull)
+ continue; /* drop null constant */
+ if (newargs == NIL)
+ return e; /* first expr */
+ newargs = lappend(newargs, e);
+ break;
+ }
newargs = lappend(newargs, e);
- break;
}
- newargs = lappend(newargs, e);
- }
- /* If all the arguments were constant null, the result is just null */
- if (newargs == NIL)
- return (Node *) makeNullConst(coalesceexpr->coalescetype,
- -1,
- coalesceexpr->coalescecollid);
-
- newcoalesce = makeNode(CoalesceExpr);
- newcoalesce->coalescetype = coalesceexpr->coalescetype;
- newcoalesce->coalescecollid = coalesceexpr->coalescecollid;
- newcoalesce->args = newargs;
- newcoalesce->location = coalesceexpr->location;
- return (Node *) newcoalesce;
- }
- if (IsA(node, FieldSelect))
- {
- /*
- * We can optimize field selection from a whole-row Var into a simple
- * Var. (This case won't be generated directly by the parser, because
- * ParseComplexProjection short-circuits it. But it can arise while
- * simplifying functions.) Also, we can optimize field selection from
- * a RowExpr construct.
- *
- * We must however check that the declared type of the field is still
- * the same as when the FieldSelect was created --- this can change if
- * someone did ALTER COLUMN TYPE on the rowtype.
- */
- FieldSelect *fselect = (FieldSelect *) node;
- FieldSelect *newfselect;
- Node *arg;
-
- arg = eval_const_expressions_mutator((Node *) fselect->arg,
- context);
- if (arg && IsA(arg, Var) &&
- ((Var *) arg)->varattno == InvalidAttrNumber)
- {
- if (rowtype_field_matches(((Var *) arg)->vartype,
- fselect->fieldnum,
- fselect->resulttype,
- fselect->resulttypmod,
- fselect->resultcollid))
- return (Node *) makeVar(((Var *) arg)->varno,
- fselect->fieldnum,
- fselect->resulttype,
- fselect->resulttypmod,
- fselect->resultcollid,
- ((Var *) arg)->varlevelsup);
+ /* If all the arguments were constant null, the result is just null */
+ if (newargs == NIL)
+ return (Node *) makeNullConst(coalesceexpr->coalescetype,
+ -1,
+ coalesceexpr->coalescecollid);
+
+ newcoalesce = makeNode(CoalesceExpr);
+ newcoalesce->coalescetype = coalesceexpr->coalescetype;
+ newcoalesce->coalescecollid = coalesceexpr->coalescecollid;
+ newcoalesce->args = newargs;
+ newcoalesce->location = coalesceexpr->location;
+ return (Node *) newcoalesce;
}
- if (arg && IsA(arg, RowExpr))
+ case T_FieldSelect:
{
- RowExpr *rowexpr = (RowExpr *) arg;
-
- if (fselect->fieldnum > 0 &&
- fselect->fieldnum <= list_length(rowexpr->args))
+ /*
+ * We can optimize field selection from a whole-row Var into a simple
+ * Var. (This case won't be generated directly by the parser, because
+ * ParseComplexProjection short-circuits it. But it can arise while
+ * simplifying functions.) Also, we can optimize field selection from
+ * a RowExpr construct.
+ *
+ * We must however check that the declared type of the field is still
+ * the same as when the FieldSelect was created --- this can change if
+ * someone did ALTER COLUMN TYPE on the rowtype.
+ */
+ FieldSelect *fselect = (FieldSelect *) node;
+ FieldSelect *newfselect;
+ Node *arg;
+
+ arg = eval_const_expressions_mutator((Node *) fselect->arg,
+ context);
+ if (arg && IsA(arg, Var) &&
+ ((Var *) arg)->varattno == InvalidAttrNumber)
{
- Node *fld = (Node *) list_nth(rowexpr->args,
- fselect->fieldnum - 1);
-
- if (rowtype_field_matches(rowexpr->row_typeid,
+ if (rowtype_field_matches(((Var *) arg)->vartype,
fselect->fieldnum,
fselect->resulttype,
fselect->resulttypmod,
- fselect->resultcollid) &&
- fselect->resulttype == exprType(fld) &&
- fselect->resulttypmod == exprTypmod(fld) &&
- fselect->resultcollid == exprCollation(fld))
- return fld;
+ fselect->resultcollid))
+ return (Node *) makeVar(((Var *) arg)->varno,
+ fselect->fieldnum,
+ fselect->resulttype,
+ fselect->resulttypmod,
+ fselect->resultcollid,
+ ((Var *) arg)->varlevelsup);
}
- }
- newfselect = makeNode(FieldSelect);
- newfselect->arg = (Expr *) arg;
- newfselect->fieldnum = fselect->fieldnum;
- newfselect->resulttype = fselect->resulttype;
- newfselect->resulttypmod = fselect->resulttypmod;
- newfselect->resultcollid = fselect->resultcollid;
- return (Node *) newfselect;
- }
- if (IsA(node, NullTest))
- {
- NullTest *ntest = (NullTest *) node;
- NullTest *newntest;
- Node *arg;
+ if (arg && IsA(arg, RowExpr))
+ {
+ RowExpr *rowexpr = (RowExpr *) arg;
- arg = eval_const_expressions_mutator((Node *) ntest->arg,
- context);
- if (arg && IsA(arg, RowExpr))
+ if (fselect->fieldnum > 0 &&
+ fselect->fieldnum <= list_length(rowexpr->args))
+ {
+ Node *fld = (Node *) list_nth(rowexpr->args,
+ fselect->fieldnum - 1);
+
+ if (rowtype_field_matches(rowexpr->row_typeid,
+ fselect->fieldnum,
+ fselect->resulttype,
+ fselect->resulttypmod,
+ fselect->resultcollid) &&
+ fselect->resulttype == exprType(fld) &&
+ fselect->resulttypmod == exprTypmod(fld) &&
+ fselect->resultcollid == exprCollation(fld))
+ return fld;
+ }
+ }
+ newfselect = makeNode(FieldSelect);
+ newfselect->arg = (Expr *) arg;
+ newfselect->fieldnum = fselect->fieldnum;
+ newfselect->resulttype = fselect->resulttype;
+ newfselect->resulttypmod = fselect->resulttypmod;
+ newfselect->resultcollid = fselect->resultcollid;
+ return (Node *) newfselect;
+ }
+ case T_NullTest:
{
- /*
- * We break ROW(...) IS [NOT] NULL into separate tests on its
- * component fields. This form is usually more efficient to
- * evaluate, as well as being more amenable to optimization.
- */
- RowExpr *rarg = (RowExpr *) arg;
- List *newargs = NIL;
- ListCell *l;
-
- Assert(ntest->argisrow);
+ NullTest *ntest = (NullTest *) node;
+ NullTest *newntest;
+ Node *arg;
- foreach(l, rarg->args)
+ arg = eval_const_expressions_mutator((Node *) ntest->arg,
+ context);
+ if (arg && IsA(arg, RowExpr))
{
- Node *relem = (Node *) lfirst(l);
-
/*
- * A constant field refutes the whole NullTest if it's of the
- * wrong nullness; else we can discard it.
+ * We break ROW(...) IS [NOT] NULL into separate tests on its
+ * component fields. This form is usually more efficient to
+ * evaluate, as well as being more amenable to optimization.
*/
- if (relem && IsA(relem, Const))
+ RowExpr *rarg = (RowExpr *) arg;
+ List *newargs = NIL;
+ ListCell *l;
+
+ Assert(ntest->argisrow);
+
+ foreach(l, rarg->args)
{
- Const *carg = (Const *) relem;
+ Node *relem = (Node *) lfirst(l);
- if (carg->constisnull ?
- (ntest->nulltesttype == IS_NOT_NULL) :
- (ntest->nulltesttype == IS_NULL))
- return makeBoolConst(false, false);
- continue;
+ /*
+ * A constant field refutes the whole NullTest if it's of the
+ * wrong nullness; else we can discard it.
+ */
+ if (relem && IsA(relem, Const))
+ {
+ Const *carg = (Const *) relem;
+
+ if (carg->constisnull ?
+ (ntest->nulltesttype == IS_NOT_NULL) :
+ (ntest->nulltesttype == IS_NULL))
+ return makeBoolConst(false, false);
+ continue;
+ }
+ newntest = makeNode(NullTest);
+ newntest->arg = (Expr *) relem;
+ newntest->nulltesttype = ntest->nulltesttype;
+ newntest->argisrow = type_is_rowtype(exprType(relem));
+ newargs = lappend(newargs, newntest);
}
- newntest = makeNode(NullTest);
- newntest->arg = (Expr *) relem;
- newntest->nulltesttype = ntest->nulltesttype;
- newntest->argisrow = type_is_rowtype(exprType(relem));
- newargs = lappend(newargs, newntest);
+ /* If all the inputs were constants, result is TRUE */
+ if (newargs == NIL)
+ return makeBoolConst(true, false);
+ /* If only one nonconst input, it's the result */
+ if (list_length(newargs) == 1)
+ return (Node *) linitial(newargs);
+ /* Else we need an AND node */
+ return (Node *) make_andclause(newargs);
}
- /* If all the inputs were constants, result is TRUE */
- if (newargs == NIL)
- return makeBoolConst(true, false);
- /* If only one nonconst input, it's the result */
- if (list_length(newargs) == 1)
- return (Node *) linitial(newargs);
- /* Else we need an AND node */
- return (Node *) make_andclause(newargs);
- }
- if (!ntest->argisrow && arg && IsA(arg, Const))
- {
- Const *carg = (Const *) arg;
- bool result;
-
- switch (ntest->nulltesttype)
+ if (!ntest->argisrow && arg && IsA(arg, Const))
{
- case IS_NULL:
- result = carg->constisnull;
- break;
- case IS_NOT_NULL:
- result = !carg->constisnull;
- break;
- default:
- elog(ERROR, "unrecognized nulltesttype: %d",
- (int) ntest->nulltesttype);
- result = false; /* keep compiler quiet */
- break;
- }
+ Const *carg = (Const *) arg;
+ bool result;
- return makeBoolConst(result, false);
- }
+ switch (ntest->nulltesttype)
+ {
+ case IS_NULL:
+ result = carg->constisnull;
+ break;
+ case IS_NOT_NULL:
+ result = !carg->constisnull;
+ break;
+ default:
+ elog(ERROR, "unrecognized nulltesttype: %d",
+ (int) ntest->nulltesttype);
+ result = false; /* keep compiler quiet */
+ break;
+ }
- newntest = makeNode(NullTest);
- newntest->arg = (Expr *) arg;
- newntest->nulltesttype = ntest->nulltesttype;
- newntest->argisrow = ntest->argisrow;
- return (Node *) newntest;
- }
- if (IsA(node, BooleanTest))
- {
- BooleanTest *btest = (BooleanTest *) node;
- BooleanTest *newbtest;
- Node *arg;
+ return makeBoolConst(result, false);
+ }
- arg = eval_const_expressions_mutator((Node *) btest->arg,
- context);
- if (arg && IsA(arg, Const))
+ newntest = makeNode(NullTest);
+ newntest->arg = (Expr *) arg;
+ newntest->nulltesttype = ntest->nulltesttype;
+ newntest->argisrow = ntest->argisrow;
+ return (Node *) newntest;
+ }
+ case T_BooleanTest:
{
- Const *carg = (Const *) arg;
- bool result;
+ BooleanTest *btest = (BooleanTest *) node;
+ BooleanTest *newbtest;
+ Node *arg;
- switch (btest->booltesttype)
+ arg = eval_const_expressions_mutator((Node *) btest->arg,
+ context);
+ if (arg && IsA(arg, Const))
{
- case IS_TRUE:
- result = (!carg->constisnull &&
- DatumGetBool(carg->constvalue));
- break;
- case IS_NOT_TRUE:
- result = (carg->constisnull ||
- !DatumGetBool(carg->constvalue));
- break;
- case IS_FALSE:
- result = (!carg->constisnull &&
- !DatumGetBool(carg->constvalue));
- break;
- case IS_NOT_FALSE:
- result = (carg->constisnull ||
- DatumGetBool(carg->constvalue));
- break;
- case IS_UNKNOWN:
- result = carg->constisnull;
- break;
- case IS_NOT_UNKNOWN:
- result = !carg->constisnull;
- break;
- default:
- elog(ERROR, "unrecognized booltesttype: %d",
- (int) btest->booltesttype);
- result = false; /* keep compiler quiet */
- break;
+ Const *carg = (Const *) arg;
+ bool result;
+
+ switch (btest->booltesttype)
+ {
+ case IS_TRUE:
+ result = (!carg->constisnull &&
+ DatumGetBool(carg->constvalue));
+ break;
+ case IS_NOT_TRUE:
+ result = (carg->constisnull ||
+ !DatumGetBool(carg->constvalue));
+ break;
+ case IS_FALSE:
+ result = (!carg->constisnull &&
+ !DatumGetBool(carg->constvalue));
+ break;
+ case IS_NOT_FALSE:
+ result = (carg->constisnull ||
+ DatumGetBool(carg->constvalue));
+ break;
+ case IS_UNKNOWN:
+ result = carg->constisnull;
+ break;
+ case IS_NOT_UNKNOWN:
+ result = !carg->constisnull;
+ break;
+ default:
+ elog(ERROR, "unrecognized booltesttype: %d",
+ (int) btest->booltesttype);
+ result = false; /* keep compiler quiet */
+ break;
+ }
+
+ return makeBoolConst(result, false);
}
- return makeBoolConst(result, false);
+ newbtest = makeNode(BooleanTest);
+ newbtest->arg = (Expr *) arg;
+ newbtest->booltesttype = btest->booltesttype;
+ return (Node *) newbtest;
}
+ case T_PlaceHolderVar:
+ if(context->estimate)
+ {
+ /*
+ * In estimation mode, just strip the PlaceHolderVar node altogether;
+ * this amounts to estimating that the contained value won't be forced
+ * to null by an outer join. In regular mode we just use the default
+ * behavior (ie, simplify the expression but leave the PlaceHolderVar
+ * node intact).
+ */
+ PlaceHolderVar *phv = (PlaceHolderVar *) node;
- newbtest = makeNode(BooleanTest);
- newbtest->arg = (Expr *) arg;
- newbtest->booltesttype = btest->booltesttype;
- return (Node *) newbtest;
- }
- if (IsA(node, PlaceHolderVar) &&context->estimate)
- {
- /*
- * In estimation mode, just strip the PlaceHolderVar node altogether;
- * this amounts to estimating that the contained value won't be forced
- * to null by an outer join. In regular mode we just use the default
- * behavior (ie, simplify the expression but leave the PlaceHolderVar
- * node intact).
- */
- PlaceHolderVar *phv = (PlaceHolderVar *) node;
-
- return eval_const_expressions_mutator((Node *) phv->phexpr,
- context);
+ return eval_const_expressions_mutator((Node *) phv->phexpr,
+ context);
+ }
+ //fall through
+ default:
+ ;
}
/*
--
1.7.7.3