Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)