* inline_function: try to expand a function call inline * * If the function is a sufficiently simple SQL-language function * (just "SELECT expression"), then we can inline it and avoid the rather * high per-call overhead of SQL functions. Furthermore, this can expose * opportunities for constant-folding within the function expression. * * We have to beware of some special cases however. A
| 4619 | * simplify the function. |
| 4620 | */ |
| 4621 | static Expr * |
| 4622 | inline_function(Oid funcid, Oid result_type, Oid result_collid, |
| 4623 | Oid input_collid, List *args, |
| 4624 | bool funcvariadic, |
| 4625 | HeapTuple func_tuple, |
| 4626 | eval_const_expressions_context *context) |
| 4627 | { |
| 4628 | Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); |
| 4629 | char *src; |
| 4630 | Datum tmp; |
| 4631 | bool isNull; |
| 4632 | MemoryContext oldcxt; |
| 4633 | MemoryContext mycxt; |
| 4634 | inline_error_callback_arg callback_arg; |
| 4635 | ErrorContextCallback sqlerrcontext; |
| 4636 | FuncExpr *fexpr; |
| 4637 | SQLFunctionParseInfoPtr pinfo; |
| 4638 | TupleDesc rettupdesc; |
| 4639 | ParseState *pstate; |
| 4640 | List *raw_parsetree_list; |
| 4641 | List *querytree_list; |
| 4642 | Query *querytree; |
| 4643 | Node *newexpr; |
| 4644 | int *usecounts; |
| 4645 | ListCell *arg; |
| 4646 | int i; |
| 4647 | |
| 4648 | /* |
| 4649 | * Forget it if the function is not SQL-language or has other showstopper |
| 4650 | * properties. (The prokind and nargs checks are just paranoia.) |
| 4651 | */ |
| 4652 | if (funcform->prolang != SQLlanguageId || |
| 4653 | funcform->prokind != PROKIND_FUNCTION || |
| 4654 | funcform->prosecdef || |
| 4655 | funcform->proretset || |
| 4656 | funcform->prorettype == RECORDOID || |
| 4657 | !heap_attisnull(func_tuple, Anum_pg_proc_proconfig, NULL) || |
| 4658 | funcform->pronargs != list_length(args)) |
| 4659 | return NULL; |
| 4660 | |
| 4661 | /* Check for recursive function, and give up trying to expand if so */ |
| 4662 | if (list_member_oid(context->active_fns, funcid)) |
| 4663 | return NULL; |
| 4664 | |
| 4665 | /* Check permission to call function (fail later, if not) */ |
| 4666 | if (pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK) |
| 4667 | return NULL; |
| 4668 | |
| 4669 | /* Check whether a plugin wants to hook function entry/exit */ |
| 4670 | if (FmgrHookIsNeeded(funcid)) |
| 4671 | return NULL; |
| 4672 | |
| 4673 | /* |
| 4674 | * Make a temporary memory context, so that we don't leak all the stuff |
| 4675 | * that parsing might create. |
| 4676 | */ |
| 4677 | mycxt = AllocSetContextCreate(CurrentMemoryContext, |
| 4678 | "inline_function", |
no test coverage detected