diff options
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 45 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 217 |
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; |