Skip to content

Commit 75b39e7

Browse files
committed
Add infrastructure for storing a VARIADIC ANY function's VARIADIC flag.
Originally we didn't bother to mark FuncExprs with any indication whether VARIADIC had been given in the source text, because there didn't seem to be any need for it at runtime. However, because we cannot fold a VARIADIC ANY function's arguments into an array (since they're not necessarily all the same type), we do actually need that information at runtime if VARIADIC ANY functions are to respond unsurprisingly to use of the VARIADIC keyword. Add the missing field, and also fix ruleutils.c so that VARIADIC ANY function calls are dumped properly. Extracted from a larger patch that also fixes concat() and format() (the only two extant VARIADIC ANY functions) to behave properly when VARIADIC is specified. This portion seems appropriate to review and commit separately. Pavel Stehule
1 parent 841a515 commit 75b39e7

File tree

12 files changed

+113
-32
lines changed

12 files changed

+113
-32
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,7 @@ _copyFuncExpr(const FuncExpr *from)
11941194
COPY_SCALAR_FIELD(funcid);
11951195
COPY_SCALAR_FIELD(funcresulttype);
11961196
COPY_SCALAR_FIELD(funcretset);
1197+
COPY_SCALAR_FIELD(funcvariadic);
11971198
COPY_SCALAR_FIELD(funcformat);
11981199
COPY_SCALAR_FIELD(funccollid);
11991200
COPY_SCALAR_FIELD(inputcollid);

src/backend/nodes/equalfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ _equalFuncExpr(const FuncExpr *a, const FuncExpr *b)
239239
COMPARE_SCALAR_FIELD(funcid);
240240
COMPARE_SCALAR_FIELD(funcresulttype);
241241
COMPARE_SCALAR_FIELD(funcretset);
242+
COMPARE_SCALAR_FIELD(funcvariadic);
242243
COMPARE_COERCIONFORM_FIELD(funcformat);
243244
COMPARE_SCALAR_FIELD(funccollid);
244245
COMPARE_SCALAR_FIELD(inputcollid);

src/backend/nodes/makefuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ makeFuncExpr(Oid funcid, Oid rettype, List *args,
461461
funcexpr->funcid = funcid;
462462
funcexpr->funcresulttype = rettype;
463463
funcexpr->funcretset = false; /* only allowed case here */
464+
funcexpr->funcvariadic = false; /* only allowed case here */
464465
funcexpr->funcformat = fformat;
465466
funcexpr->funccollid = funccollid;
466467
funcexpr->inputcollid = inputcollid;

src/backend/nodes/outfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,7 @@ _outFuncExpr(StringInfo str, const FuncExpr *node)
10001000
WRITE_OID_FIELD(funcid);
10011001
WRITE_OID_FIELD(funcresulttype);
10021002
WRITE_BOOL_FIELD(funcretset);
1003+
WRITE_BOOL_FIELD(funcvariadic);
10031004
WRITE_ENUM_FIELD(funcformat, CoercionForm);
10041005
WRITE_OID_FIELD(funccollid);
10051006
WRITE_OID_FIELD(inputcollid);

src/backend/nodes/readfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ _readFuncExpr(void)
537537
READ_OID_FIELD(funcid);
538538
READ_OID_FIELD(funcresulttype);
539539
READ_BOOL_FIELD(funcretset);
540+
READ_BOOL_FIELD(funcvariadic);
540541
READ_ENUM_FIELD(funcformat, CoercionForm);
541542
READ_OID_FIELD(funccollid);
542543
READ_OID_FIELD(inputcollid);

src/backend/optimizer/util/clauses.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ static Node *simplify_boolean_equality(Oid opno, List *args);
110110
static Expr *simplify_function(Oid funcid,
111111
Oid result_type, int32 result_typmod,
112112
Oid result_collid, Oid input_collid, List **args_p,
113-
bool process_args, bool allow_non_const,
113+
bool funcvariadic, bool process_args, bool allow_non_const,
114114
eval_const_expressions_context *context);
115115
static List *expand_function_arguments(List *args, Oid result_type,
116116
HeapTuple func_tuple);
@@ -121,10 +121,12 @@ static void recheck_cast_function_args(List *args, Oid result_type,
121121
HeapTuple func_tuple);
122122
static Expr *evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
123123
Oid result_collid, Oid input_collid, List *args,
124+
bool funcvariadic,
124125
HeapTuple func_tuple,
125126
eval_const_expressions_context *context);
126127
static Expr *inline_function(Oid funcid, Oid result_type, Oid result_collid,
127128
Oid input_collid, List *args,
129+
bool funcvariadic,
128130
HeapTuple func_tuple,
129131
eval_const_expressions_context *context);
130132
static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,
@@ -2314,6 +2316,7 @@ eval_const_expressions_mutator(Node *node,
23142316
expr->funccollid,
23152317
expr->inputcollid,
23162318
&args,
2319+
expr->funcvariadic,
23172320
true,
23182321
true,
23192322
context);
@@ -2330,6 +2333,7 @@ eval_const_expressions_mutator(Node *node,
23302333
newexpr->funcid = expr->funcid;
23312334
newexpr->funcresulttype = expr->funcresulttype;
23322335
newexpr->funcretset = expr->funcretset;
2336+
newexpr->funcvariadic = expr->funcvariadic;
23332337
newexpr->funcformat = expr->funcformat;
23342338
newexpr->funccollid = expr->funccollid;
23352339
newexpr->inputcollid = expr->inputcollid;
@@ -2359,6 +2363,7 @@ eval_const_expressions_mutator(Node *node,
23592363
expr->opcollid,
23602364
expr->inputcollid,
23612365
&args,
2366+
false,
23622367
true,
23632368
true,
23642369
context);
@@ -2464,6 +2469,7 @@ eval_const_expressions_mutator(Node *node,
24642469
&args,
24652470
false,
24662471
false,
2472+
false,
24672473
context);
24682474
if (simple) /* successfully simplified it */
24692475
{
@@ -2665,6 +2671,7 @@ eval_const_expressions_mutator(Node *node,
26652671
InvalidOid,
26662672
InvalidOid,
26672673
&args,
2674+
false,
26682675
true,
26692676
true,
26702677
context);
@@ -2697,6 +2704,7 @@ eval_const_expressions_mutator(Node *node,
26972704
InvalidOid,
26982705
&args,
26992706
false,
2707+
false,
27002708
true,
27012709
context);
27022710
if (simple) /* successfully simplified input fn */
@@ -3565,7 +3573,7 @@ simplify_boolean_equality(Oid opno, List *args)
35653573
static Expr *
35663574
simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
35673575
Oid result_collid, Oid input_collid, List **args_p,
3568-
bool process_args, bool allow_non_const,
3576+
bool funcvariadic, bool process_args, bool allow_non_const,
35693577
eval_const_expressions_context *context)
35703578
{
35713579
List *args = *args_p;
@@ -3609,7 +3617,8 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
36093617
/* Now attempt simplification of the function call proper. */
36103618

36113619
newexpr = evaluate_function(funcid, result_type, result_typmod,
3612-
result_collid, input_collid, args,
3620+
result_collid, input_collid,
3621+
args, funcvariadic,
36133622
func_tuple, context);
36143623

36153624
if (!newexpr && allow_non_const && OidIsValid(func_form->protransform))
@@ -3625,6 +3634,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
36253634
fexpr.funcid = funcid;
36263635
fexpr.funcresulttype = result_type;
36273636
fexpr.funcretset = func_form->proretset;
3637+
fexpr.funcvariadic = funcvariadic;
36283638
fexpr.funcformat = COERCE_EXPLICIT_CALL;
36293639
fexpr.funccollid = result_collid;
36303640
fexpr.inputcollid = input_collid;
@@ -3638,7 +3648,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
36383648

36393649
if (!newexpr && allow_non_const)
36403650
newexpr = inline_function(funcid, result_type, result_collid,
3641-
input_collid, args,
3651+
input_collid, args, funcvariadic,
36423652
func_tuple, context);
36433653

36443654
ReleaseSysCache(func_tuple);
@@ -3878,6 +3888,7 @@ recheck_cast_function_args(List *args, Oid result_type, HeapTuple func_tuple)
38783888
static Expr *
38793889
evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
38803890
Oid result_collid, Oid input_collid, List *args,
3891+
bool funcvariadic,
38813892
HeapTuple func_tuple,
38823893
eval_const_expressions_context *context)
38833894
{
@@ -3959,6 +3970,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
39593970
newexpr->funcid = funcid;
39603971
newexpr->funcresulttype = result_type;
39613972
newexpr->funcretset = false;
3973+
newexpr->funcvariadic = funcvariadic;
39623974
newexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */
39633975
newexpr->funccollid = result_collid; /* doesn't matter */
39643976
newexpr->inputcollid = input_collid;
@@ -4001,6 +4013,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
40014013
static Expr *
40024014
inline_function(Oid funcid, Oid result_type, Oid result_collid,
40034015
Oid input_collid, List *args,
4016+
bool funcvariadic,
40044017
HeapTuple func_tuple,
40054018
eval_const_expressions_context *context)
40064019
{
@@ -4089,6 +4102,7 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid,
40894102
fexpr->funcid = funcid;
40904103
fexpr->funcresulttype = result_type;
40914104
fexpr->funcretset = false;
4105+
fexpr->funcvariadic = funcvariadic;
40924106
fexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */
40934107
fexpr->funccollid = result_collid; /* doesn't matter */
40944108
fexpr->inputcollid = input_collid;

src/backend/parser/parse_func.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
384384
funcexpr->funcid = funcid;
385385
funcexpr->funcresulttype = rettype;
386386
funcexpr->funcretset = retset;
387+
funcexpr->funcvariadic = func_variadic;
387388
funcexpr->funcformat = COERCE_EXPLICIT_CALL;
388389
/* funccollid and inputcollid will be set by parse_collate.c */
389390
funcexpr->args = fargs;

src/backend/utils/adt/ruleutils.c

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,9 @@ static Node *processIndirection(Node *node, deparse_context *context,
396396
static void printSubscripts(ArrayRef *aref, deparse_context *context);
397397
static char *get_relation_name(Oid relid);
398398
static char *generate_relation_name(Oid relid, List *namespaces);
399-
static char *generate_function_name(Oid funcid, int nargs, List *argnames,
400-
Oid *argtypes, bool *is_variadic);
399+
static char *generate_function_name(Oid funcid, int nargs,
400+
List *argnames, Oid *argtypes,
401+
bool was_variadic, bool *use_variadic_p);
401402
static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
402403
static text *string_to_text(char *str);
403404
static char *flatten_reloptions(Oid relid);
@@ -858,7 +859,8 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
858859

859860
appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",
860861
generate_function_name(trigrec->tgfoid, 0,
861-
NIL, NULL, NULL));
862+
NIL, NULL,
863+
false, NULL));
862864

863865
if (trigrec->tgnargs > 0)
864866
{
@@ -7269,7 +7271,7 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
72697271
Oid argtypes[FUNC_MAX_ARGS];
72707272
int nargs;
72717273
List *argnames;
7272-
bool is_variadic;
7274+
bool use_variadic;
72737275
ListCell *l;
72747276

72757277
/*
@@ -7327,13 +7329,14 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
73277329
appendStringInfo(buf, "%s(",
73287330
generate_function_name(funcoid, nargs,
73297331
argnames, argtypes,
7330-
&is_variadic));
7332+
expr->funcvariadic,
7333+
&use_variadic));
73317334
nargs = 0;
73327335
foreach(l, expr->args)
73337336
{
73347337
if (nargs++ > 0)
73357338
appendStringInfoString(buf, ", ");
7336-
if (is_variadic && lnext(l) == NULL)
7339+
if (use_variadic && lnext(l) == NULL)
73377340
appendStringInfoString(buf, "VARIADIC ");
73387341
get_rule_expr((Node *) lfirst(l), context, true);
73397342
}
@@ -7374,7 +7377,8 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
73747377

73757378
appendStringInfo(buf, "%s(%s",
73767379
generate_function_name(aggref->aggfnoid, nargs,
7377-
NIL, argtypes, NULL),
7380+
NIL, argtypes,
7381+
false, NULL),
73787382
(aggref->aggdistinct != NIL) ? "DISTINCT " : "");
73797383
/* aggstar can be set only in zero-argument aggregates */
73807384
if (aggref->aggstar)
@@ -7416,7 +7420,8 @@ get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
74167420

74177421
appendStringInfo(buf, "%s(",
74187422
generate_function_name(wfunc->winfnoid, nargs,
7419-
NIL, argtypes, NULL));
7423+
NIL, argtypes,
7424+
false, NULL));
74207425
/* winstar can be set only in zero-argument aggregates */
74217426
if (wfunc->winstar)
74227427
appendStringInfoChar(buf, '*');
@@ -8507,18 +8512,25 @@ generate_relation_name(Oid relid, List *namespaces)
85078512
* given that it is being called with the specified actual arg names and
85088513
* types. (Those matter because of ambiguous-function resolution rules.)
85098514
*
8510-
* The result includes all necessary quoting and schema-prefixing. We can
8511-
* also pass back an indication of whether the function is variadic.
8515+
* If we're dealing with a potentially variadic function (in practice, this
8516+
* means a FuncExpr and not some other way of calling the function), then
8517+
* was_variadic must specify whether VARIADIC appeared in the original call,
8518+
* and *use_variadic_p will be set to indicate whether to print VARIADIC in
8519+
* the output. For non-FuncExpr cases, was_variadic should be FALSE and
8520+
* use_variadic_p can be NULL.
8521+
*
8522+
* The result includes all necessary quoting and schema-prefixing.
85128523
*/
85138524
static char *
8514-
generate_function_name(Oid funcid, int nargs, List *argnames,
8515-
Oid *argtypes, bool *is_variadic)
8525+
generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
8526+
bool was_variadic, bool *use_variadic_p)
85168527
{
8528+
char *result;
85178529
HeapTuple proctup;
85188530
Form_pg_proc procform;
85198531
char *proname;
8532+
bool use_variadic;
85208533
char *nspname;
8521-
char *result;
85228534
FuncDetailCode p_result;
85238535
Oid p_funcid;
85248536
Oid p_rettype;
@@ -8532,15 +8544,47 @@ generate_function_name(Oid funcid, int nargs, List *argnames,
85328544
procform = (Form_pg_proc) GETSTRUCT(proctup);
85338545
proname = NameStr(procform->proname);
85348546

8547+
/*
8548+
* Determine whether VARIADIC should be printed. We must do this first
8549+
* since it affects the lookup rules in func_get_detail().
8550+
*
8551+
* Currently, we always print VARIADIC if the function is variadic and
8552+
* takes a variadic type other than ANY. (In principle, if VARIADIC
8553+
* wasn't originally specified and the array actual argument is
8554+
* deconstructable, we could print the array elements separately and not
8555+
* print VARIADIC, thus more nearly reproducing the original input. For
8556+
* the moment that seems like too much complication for the benefit.)
8557+
* However, if the function takes VARIADIC ANY, then the parser didn't
8558+
* fold the arguments together into an array, so we must print VARIADIC if
8559+
* and only if it was used originally.
8560+
*/
8561+
if (use_variadic_p)
8562+
{
8563+
if (OidIsValid(procform->provariadic))
8564+
{
8565+
if (procform->provariadic != ANYOID)
8566+
use_variadic = true;
8567+
else
8568+
use_variadic = was_variadic;
8569+
}
8570+
else
8571+
use_variadic = false;
8572+
*use_variadic_p = use_variadic;
8573+
}
8574+
else
8575+
{
8576+
Assert(!was_variadic);
8577+
use_variadic = false;
8578+
}
8579+
85358580
/*
85368581
* The idea here is to schema-qualify only if the parser would fail to
85378582
* resolve the correct function given the unqualified func name with the
8538-
* specified argtypes. If the function is variadic, we should presume
8539-
* that VARIADIC will be included in the call.
8583+
* specified argtypes and VARIADIC flag.
85408584
*/
85418585
p_result = func_get_detail(list_make1(makeString(proname)),
85428586
NIL, argnames, nargs, argtypes,
8543-
!OidIsValid(procform->provariadic), true,
8587+
!use_variadic, true,
85448588
&p_funcid, &p_rettype,
85458589
&p_retset, &p_nvargs, &p_true_typeids, NULL);
85468590
if ((p_result == FUNCDETAIL_NORMAL ||
@@ -8553,17 +8597,6 @@ generate_function_name(Oid funcid, int nargs, List *argnames,
85538597

85548598
result = quote_qualified_identifier(nspname, proname);
85558599

8556-
/* Check variadic-ness if caller cares */
8557-
if (is_variadic)
8558-
{
8559-
/* "any" variadics are not treated as variadics for listing */
8560-
if (OidIsValid(procform->provariadic) &&
8561-
procform->provariadic != ANYOID)
8562-
*is_variadic = true;
8563-
else
8564-
*is_variadic = false;
8565-
}
8566-
85678600
ReleaseSysCache(proctup);
85688601

85698602
return result;

src/backend/utils/fmgr/fmgr.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2281,6 +2281,7 @@ pg_detoast_datum_packed(struct varlena * datum)
22812281
* These are needed by polymorphic functions, which accept multiple possible
22822282
* input types and need help from the parser to know what they've got.
22832283
* Also, some functions might be interested in whether a parameter is constant.
2284+
* Functions taking VARIADIC ANY also need to know about the VARIADIC keyword.
22842285
*-------------------------------------------------------------------------
22852286
*/
22862287

@@ -2445,3 +2446,28 @@ get_call_expr_arg_stable(Node *expr, int argnum)
24452446

24462447
return false;
24472448
}
2449+
2450+
/*
2451+
* Get the VARIADIC flag from the function invocation
2452+
*
2453+
* Returns false (the default assumption) if information is not available
2454+
*/
2455+
bool
2456+
get_fn_expr_variadic(FmgrInfo *flinfo)
2457+
{
2458+
Node *expr;
2459+
2460+
/*
2461+
* can't return anything useful if we have no FmgrInfo or if its fn_expr
2462+
* node has not been initialized
2463+
*/
2464+
if (!flinfo || !flinfo->fn_expr)
2465+
return false;
2466+
2467+
expr = flinfo->fn_expr;
2468+
2469+
if (IsA(expr, FuncExpr))
2470+
return ((FuncExpr *) expr)->funcvariadic;
2471+
else
2472+
return false;
2473+
}

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201301171
56+
#define CATALOG_VERSION_NO 201301211
5757

5858
#endif

0 commit comments

Comments
 (0)