Skip to content

Commit d26888b

Browse files
committed
Move checking an explicit VARIADIC "any" argument into the parser.
This is more efficient and simpler . It does mean that an untyped NULL can no longer be used in such cases, which should be mentioned in Release Notes, but doesn't seem a terrible loss. The workaround is to cast the NULL to some array type. Pavel Stehule, reviewed by Jeevan Chalke.
1 parent 405a468 commit d26888b

File tree

7 files changed

+55
-39
lines changed

7 files changed

+55
-39
lines changed

src/backend/catalog/pg_aggregate.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ lookup_agg_function(List *fnName,
332332
Oid fnOid;
333333
bool retset;
334334
int nvargs;
335+
Oid vatype;
335336
Oid *true_oid_array;
336337
FuncDetailCode fdresult;
337338
AclResult aclresult;
@@ -346,7 +347,8 @@ lookup_agg_function(List *fnName,
346347
*/
347348
fdresult = func_get_detail(fnName, NIL, NIL,
348349
nargs, input_types, false, false,
349-
&fnOid, rettype, &retset, &nvargs,
350+
&fnOid, rettype, &retset,
351+
&nvargs, &vatype,
350352
&true_oid_array, NULL);
351353

352354
/* only valid case is a normal function not returning a set */

src/backend/parser/parse_func.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
7979
Node *retval;
8080
bool retset;
8181
int nvargs;
82+
Oid vatype;
8283
FuncDetailCode fdresult;
8384

8485
/*
@@ -214,7 +215,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
214215
fdresult = func_get_detail(funcname, fargs, argnames, nargs,
215216
actual_arg_types,
216217
!func_variadic, true,
217-
&funcid, &rettype, &retset, &nvargs,
218+
&funcid, &rettype, &retset,
219+
&nvargs, &vatype,
218220
&declared_arg_types, &argdefaults);
219221
if (fdresult == FUNCDETAIL_COERCION)
220222
{
@@ -382,6 +384,22 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
382384
fargs = lappend(fargs, newa);
383385
}
384386

387+
/*
388+
* When function is called an explicit VARIADIC labeled parameter,
389+
* and the declared_arg_type is "any", then sanity check the actual
390+
* parameter type now - it must be an array.
391+
*/
392+
if (nargs > 0 && vatype == ANYOID && func_variadic)
393+
{
394+
Oid va_arr_typid = actual_arg_types[nargs - 1];
395+
396+
if (!OidIsValid(get_element_type(va_arr_typid)))
397+
ereport(ERROR,
398+
(errcode(ERRCODE_DATATYPE_MISMATCH),
399+
errmsg("VARIADIC argument must be an array"),
400+
parser_errposition(pstate, exprLocation((Node *) llast(fargs)))));
401+
}
402+
385403
/* build the appropriate output structure */
386404
if (fdresult == FUNCDETAIL_NORMAL)
387405
{
@@ -1033,6 +1051,7 @@ func_get_detail(List *funcname,
10331051
Oid *rettype, /* return value */
10341052
bool *retset, /* return value */
10351053
int *nvargs, /* return value */
1054+
Oid *vatype, /* return value */
10361055
Oid **true_typeids, /* return value */
10371056
List **argdefaults) /* optional return value */
10381057
{
@@ -1251,6 +1270,7 @@ func_get_detail(List *funcname,
12511270
pform = (Form_pg_proc) GETSTRUCT(ftup);
12521271
*rettype = pform->prorettype;
12531272
*retset = pform->proretset;
1273+
*vatype = pform->provariadic;
12541274
/* fetch default args if caller wants 'em */
12551275
if (argdefaults && best_candidate->ndargs > 0)
12561276
{

src/backend/utils/adt/ruleutils.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8584,6 +8584,7 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
85848584
Oid p_rettype;
85858585
bool p_retset;
85868586
int p_nvargs;
8587+
Oid p_vatype;
85878588
Oid *p_true_typeids;
85888589

85898590
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
@@ -8634,7 +8635,8 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
86348635
NIL, argnames, nargs, argtypes,
86358636
!use_variadic, true,
86368637
&p_funcid, &p_rettype,
8637-
&p_retset, &p_nvargs, &p_true_typeids, NULL);
8638+
&p_retset, &p_nvargs, &p_vatype,
8639+
&p_true_typeids, NULL);
86388640
if ((p_result == FUNCDETAIL_NORMAL ||
86398641
p_result == FUNCDETAIL_AGGREGATE ||
86408642
p_result == FUNCDETAIL_WINDOWFUNC) &&

src/backend/utils/adt/varlena.c

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3820,7 +3820,6 @@ concat_internal(const char *sepstr, int argidx,
38203820
*/
38213821
if (get_fn_expr_variadic(fcinfo->flinfo))
38223822
{
3823-
Oid arr_typid;
38243823
ArrayType *arr;
38253824

38263825
/* Should have just the one argument */
@@ -3831,20 +3830,16 @@ concat_internal(const char *sepstr, int argidx,
38313830
return NULL;
38323831

38333832
/*
3834-
* Non-null argument had better be an array. The parser doesn't
3835-
* enforce this for VARIADIC ANY functions (maybe it should?), so that
3836-
* check uses ereport not just elog.
3833+
* Non-null argument had better be an array
3834+
*
3835+
* Correct values are ensured by parser check, but this function
3836+
* can be called directly, bypassing the parser, so we should do
3837+
* some minimal check too - this form of call requires correctly set
3838+
* expr argtype in flinfo.
38373839
*/
3838-
arr_typid = get_fn_expr_argtype(fcinfo->flinfo, argidx);
3839-
if (!OidIsValid(arr_typid))
3840-
elog(ERROR, "could not determine data type of concat() input");
3841-
3842-
if (!OidIsValid(get_element_type(arr_typid)))
3843-
ereport(ERROR,
3844-
(errcode(ERRCODE_DATATYPE_MISMATCH),
3845-
errmsg("VARIADIC argument must be an array")));
3840+
Assert(OidIsValid(get_fn_expr_argtype(fcinfo->flinfo, argidx)));
3841+
Assert(OidIsValid(get_element_type(get_fn_expr_argtype(fcinfo->flinfo, argidx))));
38463842

3847-
/* OK, safe to fetch the array value */
38483843
arr = PG_GETARG_ARRAYTYPE_P(argidx);
38493844

38503845
/*
@@ -4049,7 +4044,6 @@ text_format(PG_FUNCTION_ARGS)
40494044
/* If argument is marked VARIADIC, expand array into elements */
40504045
if (get_fn_expr_variadic(fcinfo->flinfo))
40514046
{
4052-
Oid arr_typid;
40534047
ArrayType *arr;
40544048
int16 elmlen;
40554049
bool elmbyval;
@@ -4065,20 +4059,16 @@ text_format(PG_FUNCTION_ARGS)
40654059
else
40664060
{
40674061
/*
4068-
* Non-null argument had better be an array. The parser doesn't
4069-
* enforce this for VARIADIC ANY functions (maybe it should?), so
4070-
* that check uses ereport not just elog.
4062+
* Non-null argument had better be an array
4063+
*
4064+
* Correct values are ensured by parser check, but this function
4065+
* can be called directly, bypassing the parser, so we should do
4066+
* some minimal check too - this form of call requires correctly set
4067+
* expr argtype in flinfo.
40714068
*/
4072-
arr_typid = get_fn_expr_argtype(fcinfo->flinfo, 1);
4073-
if (!OidIsValid(arr_typid))
4074-
elog(ERROR, "could not determine data type of format() input");
4075-
4076-
if (!OidIsValid(get_element_type(arr_typid)))
4077-
ereport(ERROR,
4078-
(errcode(ERRCODE_DATATYPE_MISMATCH),
4079-
errmsg("VARIADIC argument must be an array")));
4069+
Assert(OidIsValid(get_fn_expr_argtype(fcinfo->flinfo, 1)));
4070+
Assert(OidIsValid(get_element_type(get_fn_expr_argtype(fcinfo->flinfo, 1))));
40804071

4081-
/* OK, safe to fetch the array value */
40824072
arr = PG_GETARG_ARRAYTYPE_P(1);
40834073

40844074
/* Get info about array element type */

src/include/parser/parse_func.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ extern FuncDetailCode func_get_detail(List *funcname,
5252
int nargs, Oid *argtypes,
5353
bool expand_variadic, bool expand_defaults,
5454
Oid *funcid, Oid *rettype,
55-
bool *retset, int *nvargs, Oid **true_typeids,
56-
List **argdefaults);
55+
bool *retset, int *nvargs, Oid *vatype,
56+
Oid **true_typeids, List **argdefaults);
5757

5858
extern int func_match_argtypes(int nargs,
5959
Oid *input_typeids,

src/test/regress/expected/text.out

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,13 @@ select concat_ws(',', variadic array[1,2,3]);
149149
1,2,3
150150
(1 row)
151151

152-
select concat_ws(',', variadic NULL);
152+
select concat_ws(',', variadic NULL::int[]);
153153
concat_ws
154154
-----------
155155

156156
(1 row)
157157

158-
select concat(variadic NULL) is NULL;
158+
select concat(variadic NULL::int[]) is NULL;
159159
?column?
160160
----------
161161
t
@@ -170,6 +170,8 @@ select concat(variadic '{}'::int[]) = '';
170170
--should fail
171171
select concat_ws(',', variadic 10);
172172
ERROR: VARIADIC argument must be an array
173+
LINE 1: select concat_ws(',', variadic 10);
174+
^
173175
/*
174176
* format
175177
*/
@@ -315,8 +317,8 @@ select format('%2$s, %1$s', variadic array[1, 2]);
315317
2, 1
316318
(1 row)
317319

318-
-- variadic argument can be NULL, but should not be referenced
319-
select format('Hello', variadic NULL);
320+
-- variadic argument can be array type NULL, but should not be referenced
321+
select format('Hello', variadic NULL::int[]);
320322
format
321323
--------
322324
Hello

src/test/regress/sql/text.sql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ select quote_literal(e'\\');
4747
-- check variadic labeled argument
4848
select concat(variadic array[1,2,3]);
4949
select concat_ws(',', variadic array[1,2,3]);
50-
select concat_ws(',', variadic NULL);
51-
select concat(variadic NULL) is NULL;
50+
select concat_ws(',', variadic NULL::int[]);
51+
select concat(variadic NULL::int[]) is NULL;
5252
select concat(variadic '{}'::int[]) = '';
5353
--should fail
5454
select concat_ws(',', variadic 10);
@@ -93,8 +93,8 @@ select format('%s, %s', variadic array[true, false]::text[]);
9393
-- check variadic with positional placeholders
9494
select format('%2$s, %1$s', variadic array['first', 'second']);
9595
select format('%2$s, %1$s', variadic array[1, 2]);
96-
-- variadic argument can be NULL, but should not be referenced
97-
select format('Hello', variadic NULL);
96+
-- variadic argument can be array type NULL, but should not be referenced
97+
select format('Hello', variadic NULL::int[]);
9898
-- variadic argument allows simulating more than FUNC_MAX_ARGS parameters
9999
select format(string_agg('%s',','), variadic array_agg(i))
100100
from generate_series(1,200) g(i);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy