diff options
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 106 |
1 files changed, 73 insertions, 33 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 7b31b6b4fa6..0fddbae60a3 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -118,8 +118,8 @@ static Expr *evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, Oid input_collid, List *args, HeapTuple func_tuple, eval_const_expressions_context *context); -static Expr *inline_function(Oid funcid, Oid result_type, List *args, - HeapTuple func_tuple, +static Expr *inline_function(Oid funcid, Oid result_type, Oid input_collid, + List *args, HeapTuple func_tuple, eval_const_expressions_context *context); static Node *substitute_actual_parameters(Node *expr, int nargs, List *args, int *usecounts); @@ -3431,7 +3431,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod, func_tuple, context); if (!newexpr && allow_inline) - newexpr = inline_function(funcid, result_type, *args, + newexpr = inline_function(funcid, result_type, input_collid, *args, func_tuple, context); ReleaseSysCache(func_tuple); @@ -3798,12 +3798,11 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, * simplify the function. */ static Expr * -inline_function(Oid funcid, Oid result_type, List *args, +inline_function(Oid funcid, Oid result_type, Oid input_collid, List *args, HeapTuple func_tuple, eval_const_expressions_context *context) { Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); - Oid *argtypes; char *src; Datum tmp; bool isNull; @@ -3812,6 +3811,9 @@ inline_function(Oid funcid, Oid result_type, List *args, MemoryContext mycxt; inline_error_callback_arg callback_arg; ErrorContextCallback sqlerrcontext; + FuncExpr *fexpr; + SQLFunctionParseInfoPtr pinfo; + ParseState *pstate; List *raw_parsetree_list; Query *querytree; Node *newexpr; @@ -3875,17 +3877,25 @@ inline_function(Oid funcid, Oid result_type, List *args, sqlerrcontext.previous = error_context_stack; error_context_stack = &sqlerrcontext; - /* Check for polymorphic arguments, and substitute actual arg types */ - argtypes = (Oid *) palloc(funcform->pronargs * sizeof(Oid)); - memcpy(argtypes, funcform->proargtypes.values, - funcform->pronargs * sizeof(Oid)); - for (i = 0; i < funcform->pronargs; i++) - { - if (IsPolymorphicType(argtypes[i])) - { - argtypes[i] = exprType((Node *) list_nth(args, i)); - } - } + /* + * Set up to handle parameters while parsing the function body. We need a + * dummy FuncExpr node containing the already-simplified arguments to pass + * to prepare_sql_fn_parse_info. (It is really only needed if there are + * some polymorphic arguments, but for simplicity we always build it.) + */ + fexpr = makeNode(FuncExpr); + fexpr->funcid = funcid; + fexpr->funcresulttype = result_type; + fexpr->funcretset = false; + fexpr->funcformat = COERCE_DONTCARE; /* doesn't matter */ + fexpr->funccollid = InvalidOid; /* doesn't matter */ + fexpr->inputcollid = input_collid; + fexpr->args = args; + fexpr->location = -1; + + pinfo = prepare_sql_fn_parse_info(func_tuple, + (Node *) fexpr, + input_collid); /* * We just do parsing and parse analysis, not rewriting, because rewriting @@ -3897,8 +3907,13 @@ inline_function(Oid funcid, Oid result_type, List *args, if (list_length(raw_parsetree_list) != 1) goto fail; - querytree = parse_analyze(linitial(raw_parsetree_list), src, - argtypes, funcform->pronargs); + pstate = make_parsestate(NULL); + pstate->p_sourcetext = src; + sql_fn_parser_setup(pstate, pinfo); + + querytree = transformStmt(pstate, linitial(raw_parsetree_list)); + + free_parsestate(pstate); /* * The single command must be a simple "SELECT expression". @@ -4031,6 +4046,28 @@ inline_function(Oid funcid, Oid result_type, List *args, MemoryContextDelete(mycxt); /* + * If the result is of a collatable type, force the result to expose + * the correct collation. In most cases this does not matter, but + * it's possible that the function result is used directly as a sort key + * or in other places where we expect exprCollation() to tell the truth. + */ + if (OidIsValid(input_collid)) + { + Oid exprcoll = exprCollation(newexpr); + + if (OidIsValid(exprcoll) && exprcoll != input_collid) + { + CollateExpr *newnode = makeNode(CollateExpr); + + newnode->arg = (Expr *) newexpr; + newnode->collOid = input_collid; + newnode->location = -1; + + newexpr = (Node *) newnode; + } + } + + /* * Since there is now no trace of the function in the plan tree, we must * explicitly record the plan's dependency on the function. */ @@ -4219,7 +4256,6 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) Oid func_oid; HeapTuple func_tuple; Form_pg_proc funcform; - Oid *argtypes; char *src; Datum tmp; bool isNull; @@ -4229,10 +4265,10 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) List *saveInvalItems; inline_error_callback_arg callback_arg; ErrorContextCallback sqlerrcontext; + SQLFunctionParseInfoPtr pinfo; List *raw_parsetree_list; List *querytree_list; Query *querytree; - int i; Assert(rte->rtekind == RTE_FUNCTION); @@ -4366,17 +4402,14 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) if (list_length(fexpr->args) != funcform->pronargs) goto fail; - /* Check for polymorphic arguments, and substitute actual arg types */ - argtypes = (Oid *) palloc(funcform->pronargs * sizeof(Oid)); - memcpy(argtypes, funcform->proargtypes.values, - funcform->pronargs * sizeof(Oid)); - for (i = 0; i < funcform->pronargs; i++) - { - if (IsPolymorphicType(argtypes[i])) - { - argtypes[i] = exprType((Node *) list_nth(fexpr->args, i)); - } - } + /* + * Set up to handle parameters while parsing the function body. We + * can use the FuncExpr just created as the input for + * prepare_sql_fn_parse_info. + */ + pinfo = prepare_sql_fn_parse_info(func_tuple, + (Node *) fexpr, + fexpr->inputcollid); /* * Parse, analyze, and rewrite (unlike inline_function(), we can't skip @@ -4387,8 +4420,10 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) if (list_length(raw_parsetree_list) != 1) goto fail; - querytree_list = pg_analyze_and_rewrite(linitial(raw_parsetree_list), src, - argtypes, funcform->pronargs); + querytree_list = pg_analyze_and_rewrite_params(linitial(raw_parsetree_list), + src, + (ParserSetupHook) sql_fn_parser_setup, + pinfo); if (list_length(querytree_list) != 1) goto fail; querytree = linitial(querytree_list); @@ -4462,6 +4497,11 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) ReleaseSysCache(func_tuple); /* + * We don't have to fix collations here because the upper query is + * already parsed, ie, the collations in the RTE are what count. + */ + + /* * Since there is now no trace of the function in the plan tree, we must * explicitly record the plan's dependency on the function. */ |