@@ -49,15 +49,17 @@ static Node *ParseComplexProjection(ParseState *pstate, const char *funcname,
49
49
* For historical reasons, Postgres tries to treat the notations tab.col
50
50
* and col(tab) as equivalent: if a single-argument function call has an
51
51
* argument of complex type and the (unqualified) function name matches
52
- * any attribute of the type, we take it as a column projection. Conversely
53
- * a function of a single complex-type argument can be written like a
54
- * column reference, allowing functions to act like computed columns.
52
+ * any attribute of the type, we can interpret it as a column projection.
53
+ * Conversely a function of a single complex-type argument can be written
54
+ * like a column reference, allowing functions to act like computed columns.
55
+ *
56
+ * If both interpretations are possible, we prefer the one matching the
57
+ * syntactic form, but otherwise the form does not matter.
55
58
*
56
59
* Hence, both cases come through here. If fn is null, we're dealing with
57
- * column syntax not function syntax, but in principle that should not
58
- * affect the lookup behavior, only which error messages we deliver.
59
- * The FuncCall struct is needed however to carry various decoration that
60
- * applies to aggregate and window functions.
60
+ * column syntax not function syntax. In the function-syntax case,
61
+ * the FuncCall struct is needed to carry various decoration that applies
62
+ * to aggregate and window functions.
61
63
*
62
64
* Also, when fn is null, we return NULL on failure rather than
63
65
* reporting a no-such-function error.
@@ -84,6 +86,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
84
86
bool agg_distinct = (fn ? fn -> agg_distinct : false);
85
87
bool func_variadic = (fn ? fn -> func_variadic : false);
86
88
WindowDef * over = (fn ? fn -> over : NULL );
89
+ bool could_be_projection ;
87
90
Oid rettype ;
88
91
Oid funcid ;
89
92
ListCell * l ;
@@ -202,36 +205,39 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
202
205
}
203
206
204
207
/*
205
- * Check for column projection: if function has one argument, and that
206
- * argument is of complex type, and function name is not qualified, then
207
- * the "function call" could be a projection. We also check that there
208
- * wasn't any aggregate or variadic decoration, nor an argument name.
208
+ * Decide whether it's legitimate to consider the construct to be a column
209
+ * projection. For that, there has to be a single argument of complex
210
+ * type, the function name must not be qualified, and there cannot be any
211
+ * syntactic decoration that'd require it to be a function (such as
212
+ * aggregate or variadic decoration, or named arguments).
209
213
*/
210
- if (nargs == 1 && !proc_call &&
211
- agg_order == NIL && agg_filter == NULL && !agg_star &&
212
- !agg_distinct && over == NULL && !func_variadic && argnames == NIL &&
213
- list_length (funcname ) == 1 )
214
- {
215
- Oid argtype = actual_arg_types [0 ];
214
+ could_be_projection = (nargs == 1 && !proc_call &&
215
+ agg_order == NIL && agg_filter == NULL &&
216
+ !agg_star && !agg_distinct && over == NULL &&
217
+ !func_variadic && argnames == NIL &&
218
+ list_length (funcname ) == 1 &&
219
+ (actual_arg_types [0 ] == RECORDOID ||
220
+ ISCOMPLEX (actual_arg_types [0 ])));
216
221
217
- if (argtype == RECORDOID || ISCOMPLEX (argtype ))
218
- {
219
- retval = ParseComplexProjection (pstate ,
220
- strVal (linitial (funcname )),
221
- first_arg ,
222
- location );
223
- if (retval )
224
- return retval ;
222
+ /*
223
+ * If it's column syntax, check for column projection case first.
224
+ */
225
+ if (could_be_projection && is_column )
226
+ {
227
+ retval = ParseComplexProjection (pstate ,
228
+ strVal (linitial (funcname )),
229
+ first_arg ,
230
+ location );
231
+ if (retval )
232
+ return retval ;
225
233
226
- /*
227
- * If ParseComplexProjection doesn't recognize it as a projection,
228
- * just press on.
229
- */
230
- }
234
+ /*
235
+ * If ParseComplexProjection doesn't recognize it as a projection,
236
+ * just press on.
237
+ */
231
238
}
232
239
233
240
/*
234
- * Okay, it's not a column projection, so it must really be a function.
235
241
* func_get_detail looks up the function in the catalogs, does
236
242
* disambiguation for polymorphic functions, handles inheritance, and
237
243
* returns the funcid and type and set or singleton status of the
@@ -334,7 +340,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
334
340
}
335
341
336
342
/*
337
- * So far so good, so do some routine -type-specific processing.
343
+ * So far so good, so do some fdresult -type-specific processing.
338
344
*/
339
345
if (fdresult == FUNCDETAIL_NORMAL || fdresult == FUNCDETAIL_PROCEDURE )
340
346
{
@@ -524,30 +530,55 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
524
530
actual_arg_types [0 ], rettype , -1 ,
525
531
COERCION_EXPLICIT , COERCE_EXPLICIT_CALL , location );
526
532
}
533
+ else if (fdresult == FUNCDETAIL_MULTIPLE )
534
+ {
535
+ /*
536
+ * We found multiple possible functional matches. If we are dealing
537
+ * with attribute notation, return failure, letting the caller report
538
+ * "no such column" (we already determined there wasn't one). If
539
+ * dealing with function notation, report "ambiguous function",
540
+ * regardless of whether there's also a column by this name.
541
+ */
542
+ if (is_column )
543
+ return NULL ;
544
+
545
+ ereport (ERROR ,
546
+ (errcode (ERRCODE_AMBIGUOUS_FUNCTION ),
547
+ errmsg ("function %s is not unique" ,
548
+ func_signature_string (funcname , nargs , argnames ,
549
+ actual_arg_types )),
550
+ errhint ("Could not choose a best candidate function. "
551
+ "You might need to add explicit type casts." ),
552
+ parser_errposition (pstate , location )));
553
+ }
527
554
else
528
555
{
529
556
/*
530
- * Oops. Time to die.
531
- *
532
- * If we are dealing with the attribute notation rel.function, let the
533
- * caller handle failure.
557
+ * Not found as a function. If we are dealing with attribute
558
+ * notation, return failure, letting the caller report "no such
559
+ * column" (we already determined there wasn't one).
534
560
*/
535
561
if (is_column )
536
562
return NULL ;
537
563
538
564
/*
539
- * Else generate a detailed complaint for a function
565
+ * Check for column projection interpretation, since we didn't before.
540
566
*/
541
- if (fdresult == FUNCDETAIL_MULTIPLE )
542
- ereport (ERROR ,
543
- (errcode (ERRCODE_AMBIGUOUS_FUNCTION ),
544
- errmsg ("function %s is not unique" ,
545
- func_signature_string (funcname , nargs , argnames ,
546
- actual_arg_types )),
547
- errhint ("Could not choose a best candidate function. "
548
- "You might need to add explicit type casts." ),
549
- parser_errposition (pstate , location )));
550
- else if (list_length (agg_order ) > 1 && !agg_within_group )
567
+ if (could_be_projection )
568
+ {
569
+ retval = ParseComplexProjection (pstate ,
570
+ strVal (linitial (funcname )),
571
+ first_arg ,
572
+ location );
573
+ if (retval )
574
+ return retval ;
575
+ }
576
+
577
+ /*
578
+ * No function, and no column either. Since we're dealing with
579
+ * function notation, report "function does not exist".
580
+ */
581
+ if (list_length (agg_order ) > 1 && !agg_within_group )
551
582
{
552
583
/* It's agg(x, ORDER BY y,z) ... perhaps misplaced ORDER BY */
553
584
ereport (ERROR ,
0 commit comments