Skip to content

Commit 0dcf68e

Browse files
committed
Fix some minor error-checking oversights in ParseFuncOrColumn().
Recent additions to ParseFuncOrColumn to make it reject non-procedure functions in CALL were neither adequate nor documented. Reorganize the code to ensure uniform results for all the cases that should be rejected. Also, use ERRCODE_WRONG_OBJECT_TYPE for this case as well as the converse case of a procedure in a non-CALL context. The original coding used ERRCODE_UNDEFINED_FUNCTION which seems wrong, and is certainly inconsistent with the adjacent wrong-kind-of-routine errors. This reorganization also causes the checks for aggregate decoration with a non-aggregate function to be made in the FUNCDETAIL_COERCION case; that they were not is a long-standing oversight. Discussion: https://postgr.es/m/14497.1529089235@sss.pgh.pa.us
1 parent 15378c1 commit 0dcf68e

File tree

2 files changed

+57
-42
lines changed

2 files changed

+57
-42
lines changed

src/backend/parser/parse_func.c

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ static Node *ParseComplexProjection(ParseState *pstate, const char *funcname,
6868
* last_srf should be a copy of pstate->p_last_srf from just before we
6969
* started transforming fargs. If the caller knows that fargs couldn't
7070
* contain any SRF calls, last_srf can just be pstate->p_last_srf.
71+
*
72+
* proc_call is true if we are considering a CALL statement, so that the
73+
* name must resolve to a procedure name, not anything else.
7174
*/
7275
Node *
7376
ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
@@ -204,7 +207,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
204207
* the "function call" could be a projection. We also check that there
205208
* wasn't any aggregate or variadic decoration, nor an argument name.
206209
*/
207-
if (nargs == 1 && agg_order == NIL && agg_filter == NULL && !agg_star &&
210+
if (nargs == 1 && !proc_call &&
211+
agg_order == NIL && agg_filter == NULL && !agg_star &&
208212
!agg_distinct && over == NULL && !func_variadic && argnames == NIL &&
209213
list_length(funcname) == 1)
210214
{
@@ -253,21 +257,42 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
253257

254258
cancel_parser_errposition_callback(&pcbstate);
255259

256-
if (fdresult == FUNCDETAIL_COERCION)
257-
{
258-
/*
259-
* We interpreted it as a type coercion. coerce_type can handle these
260-
* cases, so why duplicate code...
261-
*/
262-
return coerce_type(pstate, linitial(fargs),
263-
actual_arg_types[0], rettype, -1,
264-
COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location);
265-
}
266-
else if (fdresult == FUNCDETAIL_NORMAL || fdresult == FUNCDETAIL_PROCEDURE)
260+
/*
261+
* Check for various wrong-kind-of-routine cases.
262+
*/
263+
264+
/* If this is a CALL, reject things that aren't procedures */
265+
if (proc_call &&
266+
(fdresult == FUNCDETAIL_NORMAL ||
267+
fdresult == FUNCDETAIL_AGGREGATE ||
268+
fdresult == FUNCDETAIL_WINDOWFUNC ||
269+
fdresult == FUNCDETAIL_COERCION))
270+
ereport(ERROR,
271+
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
272+
errmsg("%s is not a procedure",
273+
func_signature_string(funcname, nargs,
274+
argnames,
275+
actual_arg_types)),
276+
errhint("To call a function, use SELECT."),
277+
parser_errposition(pstate, location)));
278+
/* Conversely, if not a CALL, reject procedures */
279+
if (fdresult == FUNCDETAIL_PROCEDURE && !proc_call)
280+
ereport(ERROR,
281+
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
282+
errmsg("%s is a procedure",
283+
func_signature_string(funcname, nargs,
284+
argnames,
285+
actual_arg_types)),
286+
errhint("To call a procedure, use CALL."),
287+
parser_errposition(pstate, location)));
288+
289+
if (fdresult == FUNCDETAIL_NORMAL ||
290+
fdresult == FUNCDETAIL_PROCEDURE ||
291+
fdresult == FUNCDETAIL_COERCION)
267292
{
268293
/*
269-
* Normal function found; was there anything indicating it must be an
270-
* aggregate?
294+
* In these cases, complain if there was anything indicating it must
295+
* be an aggregate or window function.
271296
*/
272297
if (agg_star)
273298
ereport(ERROR,
@@ -306,26 +331,14 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
306331
errmsg("OVER specified, but %s is not a window function nor an aggregate function",
307332
NameListToString(funcname)),
308333
parser_errposition(pstate, location)));
334+
}
309335

310-
if (fdresult == FUNCDETAIL_NORMAL && proc_call)
311-
ereport(ERROR,
312-
(errcode(ERRCODE_UNDEFINED_FUNCTION),
313-
errmsg("%s is not a procedure",
314-
func_signature_string(funcname, nargs,
315-
argnames,
316-
actual_arg_types)),
317-
errhint("To call a function, use SELECT."),
318-
parser_errposition(pstate, location)));
319-
320-
if (fdresult == FUNCDETAIL_PROCEDURE && !proc_call)
321-
ereport(ERROR,
322-
(errcode(ERRCODE_UNDEFINED_FUNCTION),
323-
errmsg("%s is a procedure",
324-
func_signature_string(funcname, nargs,
325-
argnames,
326-
actual_arg_types)),
327-
errhint("To call a procedure, use CALL."),
328-
parser_errposition(pstate, location)));
336+
/*
337+
* So far so good, so do some routine-type-specific processing.
338+
*/
339+
if (fdresult == FUNCDETAIL_NORMAL || fdresult == FUNCDETAIL_PROCEDURE)
340+
{
341+
/* Nothing special to do for these cases. */
329342
}
330343
else if (fdresult == FUNCDETAIL_AGGREGATE)
331344
{
@@ -336,15 +349,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
336349
Form_pg_aggregate classForm;
337350
int catDirectArgs;
338351

339-
if (proc_call)
340-
ereport(ERROR,
341-
(errcode(ERRCODE_UNDEFINED_FUNCTION),
342-
errmsg("%s is not a procedure",
343-
func_signature_string(funcname, nargs,
344-
argnames,
345-
actual_arg_types)),
346-
parser_errposition(pstate, location)));
347-
348352
tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcid));
349353
if (!HeapTupleIsValid(tup)) /* should not happen */
350354
elog(ERROR, "cache lookup failed for aggregate %u", funcid);
@@ -510,6 +514,16 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
510514
NameListToString(funcname)),
511515
parser_errposition(pstate, location)));
512516
}
517+
else if (fdresult == FUNCDETAIL_COERCION)
518+
{
519+
/*
520+
* We interpreted it as a type coercion. coerce_type can handle these
521+
* cases, so why duplicate code...
522+
*/
523+
return coerce_type(pstate, linitial(fargs),
524+
actual_arg_types[0], rettype, -1,
525+
COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location);
526+
}
513527
else
514528
{
515529
/*

src/test/regress/expected/create_procedure.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ CALL sum(1); -- error: not a procedure
126126
ERROR: sum(integer) is not a procedure
127127
LINE 1: CALL sum(1);
128128
^
129+
HINT: To call a function, use SELECT.
129130
CREATE PROCEDURE ptestx() LANGUAGE SQL WINDOW AS $$ INSERT INTO cp_test VALUES (1, 'a') $$;
130131
ERROR: invalid attribute in procedure definition
131132
LINE 1: CREATE PROCEDURE ptestx() LANGUAGE SQL WINDOW AS $$ INSERT 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