summaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/plan/subselect.c45
-rw-r--r--src/backend/optimizer/util/clauses.c217
2 files changed, 168 insertions, 94 deletions
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 417eecc1fe3..15d16d00221 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.73 2003/03/10 03:53:50 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.74 2003/04/08 23:20:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,7 @@
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
+#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -264,9 +265,9 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
bms_free(tmpset);
/*
- * Un-correlated or undirect correlated plans of EXISTS, EXPR, or
- * MULTIEXPR types can be used as initPlans. For EXISTS or EXPR, we
- * just produce a Param referring to the result of evaluating the
+ * Un-correlated or undirect correlated plans of EXISTS, EXPR, ARRAY, or
+ * MULTIEXPR types can be used as initPlans. For EXISTS, EXPR, or ARRAY,
+ * we just produce a Param referring to the result of evaluating the
* initPlan. For MULTIEXPR, we must build an AND or OR-clause of the
* individual comparison operators, using the appropriate lefthand
* side expressions and Params for the initPlan's target items.
@@ -291,6 +292,22 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
PlannerInitPlan = lappend(PlannerInitPlan, node);
result = (Node *) prm;
}
+ else if (node->parParam == NIL && slink->subLinkType == ARRAY_SUBLINK)
+ {
+ TargetEntry *te = lfirst(plan->targetlist);
+ Oid arraytype;
+ Param *prm;
+
+ Assert(!te->resdom->resjunk);
+ arraytype = get_array_type(te->resdom->restype);
+ if (!OidIsValid(arraytype))
+ elog(ERROR, "Cannot find array type for datatype %s",
+ format_type_be(te->resdom->restype));
+ prm = generate_new_param(arraytype, -1);
+ node->setParam = makeListi1(prm->paramid);
+ PlannerInitPlan = lappend(PlannerInitPlan, node);
+ result = (Node *) prm;
+ }
else if (node->parParam == NIL && slink->subLinkType == MULTIEXPR_SUBLINK)
{
List *exprs;
@@ -441,9 +458,6 @@ convert_sublink_opers(List *lefthand, List *operOids,
TargetEntry *te = lfirst(targetlist);
Node *rightop;
Operator tup;
- Form_pg_operator opform;
- Node *left,
- *right;
Assert(!te->resdom->resjunk);
@@ -470,28 +484,25 @@ convert_sublink_opers(List *lefthand, List *operOids,
rightop = (Node *) prm;
}
- /* Look up the operator to get its declared input types */
+ /* Look up the operator to pass to make_op_expr */
tup = SearchSysCache(OPEROID,
ObjectIdGetDatum(opid),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for operator %u", opid);
- opform = (Form_pg_operator) GETSTRUCT(tup);
/*
* Make the expression node.
*
- * Note: we use make_operand in case runtime type conversion
+ * Note: we use make_op_expr in case runtime type conversion
* function calls must be inserted for this operator!
*/
- left = make_operand(leftop, exprType(leftop), opform->oprleft);
- right = make_operand(rightop, te->resdom->restype, opform->oprright);
result = lappend(result,
- make_opclause(opid,
- opform->oprresult,
- false, /* set-result not allowed */
- (Expr *) left,
- (Expr *) right));
+ make_op_expr(tup,
+ leftop,
+ rightop,
+ exprType(leftop),
+ te->resdom->restype));
ReleaseSysCache(tup);
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 00ff202df79..72a55be667b 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.133 2003/03/22 01:49:38 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.134 2003/04/08 23:20:01 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -59,15 +59,17 @@ 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_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 Expr *simplify_function(Oid funcid, Oid result_type, List *args,
+ bool allow_inline, List *active_fns);
+static Expr *evaluate_function(Oid funcid, Oid result_type, List *args,
+ HeapTuple func_tuple);
+static Expr *inline_function(Oid funcid, Oid result_type, 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);
+static Expr *evaluate_expr(Expr *expr, Oid result_type);
/*****************************************************************************
@@ -464,6 +466,8 @@ expression_returns_set_walker(Node *node, void *context)
return false;
if (IsA(node, SubPlan))
return false;
+ if (IsA(node, ArrayExpr))
+ return false;
if (IsA(node, CoalesceExpr))
return false;
if (IsA(node, NullIfExpr))
@@ -722,6 +726,7 @@ contain_nonstrict_functions_walker(Node *node, void *context)
}
if (IsA(node, CaseExpr))
return true;
+ /* NB: ArrayExpr might someday be nonstrict */
if (IsA(node, CoalesceExpr))
return true;
if (IsA(node, NullIfExpr))
@@ -1028,7 +1033,8 @@ eval_const_expressions_mutator(Node *node, List *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);
+ simple = simplify_function(expr->funcid, expr->funcresulttype, args,
+ true, active_fns);
if (simple) /* successfully simplified it */
return (Node *) simple;
/*
@@ -1068,7 +1074,8 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* 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);
+ simple = simplify_function(expr->opfuncid, expr->opresulttype, args,
+ true, active_fns);
if (simple) /* successfully simplified it */
return (Node *) simple;
/*
@@ -1143,8 +1150,8 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* 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);
+ simple = simplify_function(expr->opfuncid, expr->opresulttype,
+ args, false, active_fns);
if (simple) /* successfully simplified it */
{
/*
@@ -1442,6 +1449,37 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
newcase->defresult = (Expr *) defresult;
return (Node *) newcase;
}
+ if (IsA(node, ArrayExpr))
+ {
+ ArrayExpr *arrayexpr = (ArrayExpr *) node;
+ ArrayExpr *newarray;
+ bool all_const = true;
+ List *newelems = NIL;
+ List *element;
+
+ foreach(element, arrayexpr->elements)
+ {
+ Node *e;
+
+ e = eval_const_expressions_mutator((Node *) lfirst(element),
+ active_fns);
+ if (!IsA(e, Const))
+ all_const = false;
+ newelems = lappend(newelems, e);
+ }
+
+ newarray = makeNode(ArrayExpr);
+ newarray->array_typeid = arrayexpr->array_typeid;
+ newarray->element_typeid = arrayexpr->element_typeid;
+ newarray->elements = newelems;
+ newarray->ndims = arrayexpr->ndims;
+
+ if (all_const)
+ return (Node *) evaluate_expr((Expr *) newarray,
+ newarray->array_typeid);
+
+ return (Node *) newarray;
+ }
if (IsA(node, CoalesceExpr))
{
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
@@ -1513,14 +1551,16 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* 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 function OID and the pre-simplified argument list;
+ * Inputs are the function OID, actual result type OID (which is needed for
+ * polymorphic functions), 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 function call.
*/
static Expr *
-simplify_function(Oid funcid, List *args, bool allow_inline, List *active_fns)
+simplify_function(Oid funcid, Oid result_type, List *args,
+ bool allow_inline, List *active_fns)
{
HeapTuple func_tuple;
Expr *newexpr;
@@ -1539,10 +1579,11 @@ simplify_function(Oid funcid, List *args, bool allow_inline, List *active_fns)
if (!HeapTupleIsValid(func_tuple))
elog(ERROR, "Function OID %u does not exist", funcid);
- newexpr = evaluate_function(funcid, args, func_tuple);
+ newexpr = evaluate_function(funcid, result_type, args, func_tuple);
if (!newexpr && allow_inline)
- newexpr = inline_function(funcid, args, func_tuple, active_fns);
+ newexpr = inline_function(funcid, result_type, args,
+ func_tuple, active_fns);
ReleaseSysCache(func_tuple);
@@ -1560,21 +1601,14 @@ simplify_function(Oid funcid, List *args, bool allow_inline, List *active_fns)
* simplify the function.
*/
static Expr *
-evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
+evaluate_function(Oid funcid, Oid result_type, List *args,
+ HeapTuple func_tuple)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
- Oid result_typeid = funcform->prorettype;
- int16 resultTypLen;
- bool resultTypByVal;
bool has_nonconst_input = false;
bool has_null_input = false;
- FuncExpr *newexpr;
- ExprState *newexprstate;
- EState *estate;
- MemoryContext oldcontext;
- Datum const_val;
- bool const_is_null;
List *arg;
+ FuncExpr *newexpr;
/*
* Can't simplify if it returns a set.
@@ -1600,7 +1634,7 @@ evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
* and even if the function is not otherwise immutable.
*/
if (funcform->proisstrict && has_null_input)
- return (Expr *) makeNullConst(result_typeid);
+ return (Expr *) makeNullConst(result_type);
/*
* Otherwise, can simplify only if the function is immutable and
@@ -1614,61 +1648,16 @@ evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
/*
* OK, looks like we can simplify this operator/function.
*
- * We use the executor's routine ExecEvalExpr() to avoid duplication of
- * code and ensure we get the same result as the executor would get.
- * To use the executor, we need an EState.
- */
- estate = CreateExecutorState();
-
- /* We can use the estate's working context to avoid memory leaks. */
- oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
-
- /*
* Build a new FuncExpr node containing the already-simplified arguments.
*/
newexpr = makeNode(FuncExpr);
newexpr->funcid = funcid;
- newexpr->funcresulttype = result_typeid;
+ newexpr->funcresulttype = result_type;
newexpr->funcretset = false;
newexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */
newexpr->args = args;
- /*
- * Prepare it for execution.
- */
- newexprstate = ExecPrepareExpr((Expr *) newexpr, estate);
-
- /*
- * And evaluate it.
- *
- * It is OK to use a default 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?
- */
- const_val = ExecEvalExprSwitchContext(newexprstate,
- GetPerTupleExprContext(estate),
- &const_is_null, NULL);
-
- /* Get info needed about result datatype */
- get_typlenbyval(result_typeid, &resultTypLen, &resultTypByVal);
-
- /* Get back to outer memory context */
- MemoryContextSwitchTo(oldcontext);
-
- /* Must copy result out of sub-context used by expression eval */
- if (!const_is_null)
- const_val = datumCopy(const_val, resultTypByVal, resultTypLen);
-
- /* Release all the junk we just created */
- FreeExecutorState(estate);
-
- /*
- * Make the constant result node.
- */
- return (Expr *) makeConst(result_typeid, resultTypLen,
- const_val, const_is_null,
- resultTypByVal);
+ return evaluate_expr((Expr *) newexpr, result_type);
}
/*
@@ -1693,11 +1682,10 @@ evaluate_function(Oid funcid, List *args, HeapTuple func_tuple)
* simplify the function.
*/
static Expr *
-inline_function(Oid funcid, List *args, HeapTuple func_tuple,
- List *active_fns)
+inline_function(Oid funcid, Oid result_type, List *args,
+ HeapTuple func_tuple, List *active_fns)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
- Oid result_typeid = funcform->prorettype;
char result_typtype;
char *src;
Datum tmp;
@@ -1723,8 +1711,8 @@ inline_function(Oid funcid, List *args, HeapTuple func_tuple,
funcform->pronargs != length(args))
return NULL;
- /* Forget it if return type is tuple or void */
- result_typtype = get_typtype(result_typeid);
+ /* Forget it if declared return type is tuple or void */
+ result_typtype = get_typtype(funcform->prorettype);
if (result_typtype != 'b' &&
result_typtype != 'd')
return NULL;
@@ -1928,6 +1916,69 @@ substitute_actual_parameters_mutator(Node *node,
(void *) context);
}
+/*
+ * evaluate_expr: pre-evaluate a constant expression
+ *
+ * We use the executor's routine ExecEvalExpr() to avoid duplication of
+ * code and ensure we get the same result as the executor would get.
+ */
+static Expr *
+evaluate_expr(Expr *expr, Oid result_type)
+{
+ EState *estate;
+ ExprState *exprstate;
+ MemoryContext oldcontext;
+ Datum const_val;
+ bool const_is_null;
+ int16 resultTypLen;
+ bool resultTypByVal;
+
+ /*
+ * To use the executor, we need an EState.
+ */
+ estate = CreateExecutorState();
+
+ /* We can use the estate's working context to avoid memory leaks. */
+ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+
+ /*
+ * Prepare expr for execution.
+ */
+ exprstate = ExecPrepareExpr(expr, estate);
+
+ /*
+ * And evaluate it.
+ *
+ * It is OK to use a default 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?
+ */
+ const_val = ExecEvalExprSwitchContext(exprstate,
+ GetPerTupleExprContext(estate),
+ &const_is_null, NULL);
+
+ /* Get info needed about result datatype */
+ get_typlenbyval(result_type, &resultTypLen, &resultTypByVal);
+
+ /* Get back to outer memory context */
+ MemoryContextSwitchTo(oldcontext);
+
+ /* Must copy result out of sub-context used by expression eval */
+ if (!const_is_null)
+ const_val = datumCopy(const_val, resultTypByVal, resultTypLen);
+
+ /* Release all the junk we just created */
+ FreeExecutorState(estate);
+
+ /*
+ * Make the constant result node.
+ */
+ return (Expr *) makeConst(result_type, resultTypLen,
+ const_val, const_is_null,
+ resultTypByVal);
+}
+
/*
* Standard expression-tree walking support
@@ -2159,6 +2210,8 @@ expression_tree_walker(Node *node,
return true;
}
break;
+ case T_ArrayExpr:
+ return walker(((ArrayExpr *) node)->elements, context);
case T_CoalesceExpr:
return walker(((CoalesceExpr *) node)->args, context);
case T_NullIfExpr:
@@ -2535,6 +2588,16 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
+ case T_ArrayExpr:
+ {
+ ArrayExpr *arrayexpr = (ArrayExpr *) node;
+ ArrayExpr *newnode;
+
+ FLATCOPY(newnode, arrayexpr, ArrayExpr);
+ MUTATE(newnode->elements, arrayexpr->elements, List *);
+ return (Node *) newnode;
+ }
+ break;
case T_CoalesceExpr:
{
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;