aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/clauses.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r--src/backend/optimizer/util/clauses.c89
1 files changed, 70 insertions, 19 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 517712a8f4c..059fa702549 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -124,10 +124,13 @@ static Expr *simplify_function(Oid funcid,
Oid result_collid, Oid input_collid, List **args_p,
bool funcvariadic, bool process_args, bool allow_non_const,
eval_const_expressions_context *context);
-static List *reorder_function_arguments(List *args, HeapTuple func_tuple);
-static List *add_function_defaults(List *args, HeapTuple func_tuple);
+static List *reorder_function_arguments(List *args, int pronargs,
+ HeapTuple func_tuple);
+static List *add_function_defaults(List *args, int pronargs,
+ HeapTuple func_tuple);
static List *fetch_function_defaults(HeapTuple func_tuple);
static void recheck_cast_function_args(List *args, Oid result_type,
+ Oid *proargtypes, int pronargs,
HeapTuple func_tuple);
static Expr *evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
Oid result_collid, Oid input_collid, List *args,
@@ -2326,7 +2329,8 @@ eval_const_expressions_mutator(Node *node,
if (!HeapTupleIsValid(func_tuple))
elog(ERROR, "cache lookup failed for function %u", funcid);
- args = expand_function_arguments(expr->args, expr->wintype,
+ args = expand_function_arguments(expr->args,
+ false, expr->wintype,
func_tuple);
ReleaseSysCache(func_tuple);
@@ -3841,7 +3845,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
*/
if (process_args)
{
- args = expand_function_arguments(args, result_type, func_tuple);
+ args = expand_function_arguments(args, false, result_type, func_tuple);
args = (List *) expression_tree_mutator((Node *) args,
eval_const_expressions_mutator,
(void *) context);
@@ -3905,6 +3909,15 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
* expand_function_arguments: convert named-notation args to positional args
* and/or insert default args, as needed
*
+ * Returns a possibly-transformed version of the args list.
+ *
+ * If include_out_arguments is true, then the args list and the result
+ * include OUT arguments.
+ *
+ * The expected result type of the call must be given, for sanity-checking
+ * purposes. Also, we ask the caller to provide the function's actual
+ * pg_proc tuple, not just its OID.
+ *
* If we need to change anything, the input argument list is copied, not
* modified.
*
@@ -3913,12 +3926,46 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
* will fall through very quickly if there's nothing to do.
*/
List *
-expand_function_arguments(List *args, Oid result_type, HeapTuple func_tuple)
+expand_function_arguments(List *args, bool include_out_arguments,
+ Oid result_type, HeapTuple func_tuple)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
+ Oid *proargtypes = funcform->proargtypes.values;
+ int pronargs = funcform->pronargs;
bool has_named_args = false;
ListCell *lc;
+ /*
+ * If we are asked to match to OUT arguments, then use the proallargtypes
+ * array (which includes those); otherwise use proargtypes (which
+ * doesn't). Of course, if proallargtypes is null, we always use
+ * proargtypes. (Fetching proallargtypes is annoyingly expensive
+ * considering that we may have nothing to do here, but fortunately the
+ * common case is include_out_arguments == false.)
+ */
+ if (include_out_arguments)
+ {
+ Datum proallargtypes;
+ bool isNull;
+
+ proallargtypes = SysCacheGetAttr(PROCOID, func_tuple,
+ Anum_pg_proc_proallargtypes,
+ &isNull);
+ if (!isNull)
+ {
+ ArrayType *arr = DatumGetArrayTypeP(proallargtypes);
+
+ pronargs = ARR_DIMS(arr)[0];
+ if (ARR_NDIM(arr) != 1 ||
+ pronargs < 0 ||
+ ARR_HASNULL(arr) ||
+ ARR_ELEMTYPE(arr) != OIDOID)
+ elog(ERROR, "proallargtypes is not a 1-D Oid array or it contains nulls");
+ Assert(pronargs >= funcform->pronargs);
+ proargtypes = (Oid *) ARR_DATA_PTR(arr);
+ }
+ }
+
/* Do we have any named arguments? */
foreach(lc, args)
{
@@ -3934,16 +3981,20 @@ expand_function_arguments(List *args, Oid result_type, HeapTuple func_tuple)
/* If so, we must apply reorder_function_arguments */
if (has_named_args)
{
- args = reorder_function_arguments(args, func_tuple);
+ args = reorder_function_arguments(args, pronargs, func_tuple);
/* Recheck argument types and add casts if needed */
- recheck_cast_function_args(args, result_type, func_tuple);
+ recheck_cast_function_args(args, result_type,
+ proargtypes, pronargs,
+ func_tuple);
}
- else if (list_length(args) < funcform->pronargs)
+ else if (list_length(args) < pronargs)
{
/* No named args, but we seem to be short some defaults */
- args = add_function_defaults(args, func_tuple);
+ args = add_function_defaults(args, pronargs, func_tuple);
/* Recheck argument types and add casts if needed */
- recheck_cast_function_args(args, result_type, func_tuple);
+ recheck_cast_function_args(args, result_type,
+ proargtypes, pronargs,
+ func_tuple);
}
return args;
@@ -3956,10 +4007,9 @@ expand_function_arguments(List *args, Oid result_type, HeapTuple func_tuple)
* impossible to form a truly valid positional call without that.
*/
static List *
-reorder_function_arguments(List *args, HeapTuple func_tuple)
+reorder_function_arguments(List *args, int pronargs, HeapTuple func_tuple)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
- int pronargs = funcform->pronargs;
int nargsprovided = list_length(args);
Node *argarray[FUNC_MAX_ARGS];
ListCell *lc;
@@ -3986,6 +4036,7 @@ reorder_function_arguments(List *args, HeapTuple func_tuple)
{
NamedArgExpr *na = (NamedArgExpr *) arg;
+ Assert(na->argnumber >= 0 && na->argnumber < pronargs);
Assert(argarray[na->argnumber] == NULL);
argarray[na->argnumber] = (Node *) na->arg;
}
@@ -4026,9 +4077,8 @@ reorder_function_arguments(List *args, HeapTuple func_tuple)
* and so we know we just need to add defaults at the end.
*/
static List *
-add_function_defaults(List *args, HeapTuple func_tuple)
+add_function_defaults(List *args, int pronargs, HeapTuple func_tuple)
{
- Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
int nargsprovided = list_length(args);
List *defaults;
int ndelete;
@@ -4037,7 +4087,7 @@ add_function_defaults(List *args, HeapTuple func_tuple)
defaults = fetch_function_defaults(func_tuple);
/* Delete any unused defaults from the list */
- ndelete = nargsprovided + list_length(defaults) - funcform->pronargs;
+ ndelete = nargsprovided + list_length(defaults) - pronargs;
if (ndelete < 0)
elog(ERROR, "not enough default arguments");
if (ndelete > 0)
@@ -4086,7 +4136,9 @@ fetch_function_defaults(HeapTuple func_tuple)
* caller should have already copied the list structure.
*/
static void
-recheck_cast_function_args(List *args, Oid result_type, HeapTuple func_tuple)
+recheck_cast_function_args(List *args, Oid result_type,
+ Oid *proargtypes, int pronargs,
+ HeapTuple func_tuple)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
int nargs;
@@ -4102,9 +4154,8 @@ recheck_cast_function_args(List *args, Oid result_type, HeapTuple func_tuple)
{
actual_arg_types[nargs++] = exprType((Node *) lfirst(lc));
}
- Assert(nargs == funcform->pronargs);
- memcpy(declared_arg_types, funcform->proargtypes.values,
- funcform->pronargs * sizeof(Oid));
+ Assert(nargs == pronargs);
+ memcpy(declared_arg_types, proargtypes, pronargs * sizeof(Oid));
rettype = enforce_generic_type_consistency(actual_arg_types,
declared_arg_types,
nargs,