@ -49,15 +49,17 @@ static Node *ParseComplexProjection(ParseState *pstate, const char *funcname,
* For historical reasons , Postgres tries to treat the notations tab . col
* and col ( tab ) as equivalent : if a single - argument function call has an
* argument of complex type and the ( unqualified ) function name matches
* any attribute of the type , we take it as a column projection . Conversely
* a function of a single complex - type argument can be written like a
* column reference , allowing functions to act like computed columns .
* any attribute of the type , we can interpret it as a column projection .
* Conversely a function of a single complex - type argument can be written
* like a column reference , allowing functions to act like computed columns .
*
* If both interpretations are possible , we prefer the one matching the
* syntactic form , but otherwise the form does not matter .
*
* Hence , both cases come through here . If fn is null , we ' re dealing with
* column syntax not function syntax , but in principle that should not
* affect the lookup behavior , only which error messages we deliver .
* The FuncCall struct is needed however to carry various decoration that
* applies to aggregate and window functions .
* column syntax not function syntax . In the function - syntax case ,
* the FuncCall struct is needed to carry various decoration that applies
* to aggregate and window functions .
*
* Also , when fn is null , we return NULL on failure rather than
* reporting a no - such - function error .
@ -84,6 +86,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
bool agg_distinct = ( fn ? fn - > agg_distinct : false ) ;
bool func_variadic = ( fn ? fn - > func_variadic : false ) ;
WindowDef * over = ( fn ? fn - > over : NULL ) ;
bool could_be_projection ;
Oid rettype ;
Oid funcid ;
ListCell * l ;
@ -202,36 +205,39 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
}
/*
* Check for column projection : if function has one argument , and that
* argument is of complex type , and function name is not qualified , then
* the " function call " could be a projection . We also check that there
* wasn ' t any aggregate or variadic decoration , nor an argument name .
* Decide whether it ' s legitimate to consider the construct to be a column
* projection . For that , there has to be a single argument of complex
* type , the function name must not be qualified , and there cannot be any
* syntactic decoration that ' d require it to be a function ( such as
* aggregate or variadic decoration , or named arguments ) .
*/
if ( nargs = = 1 & & ! proc_call & &
agg_order = = NIL & & agg_filter = = NULL & & ! agg_star & &
! agg_distinct & & over = = NULL & & ! func_variadic & & argnames = = NIL & &
list_length ( funcname ) = = 1 )
{
Oid argtype = actual_arg_types [ 0 ] ;
could_be_projection = ( nargs = = 1 & & ! proc_call & &
agg_order = = NIL & & agg_filter = = NULL & &
! agg_star & & ! agg_distinct & & over = = NULL & &
! func_variadic & & argnames = = NIL & &
list_length ( funcname ) = = 1 & &
( actual_arg_types [ 0 ] = = RECORDOID | |
ISCOMPLEX ( actual_arg_types [ 0 ] ) ) ) ;
if ( argtype = = RECORDOID | | ISCOMPLEX ( argtype ) )
{
retval = ParseComplexProjection ( pstate ,
strVal ( linitial ( funcname ) ) ,
first_arg ,
location ) ;
if ( retval )
return retval ;
/*
* If it ' s column syntax , check for column projection case first .
*/
if ( could_be_projection & & is_column )
{
retval = ParseComplexProjection ( pstate ,
strVal ( linitial ( funcname ) ) ,
first_arg ,
location ) ;
if ( retval )
return retval ;
/*
* If ParseComplexProjection doesn ' t recognize it as a projection ,
* just press on .
*/
}
/*
* If ParseComplexProjection doesn ' t recognize it as a projection ,
* just press on .
*/
}
/*
* Okay , it ' s not a column projection , so it must really be a function .
* func_get_detail looks up the function in the catalogs , does
* disambiguation for polymorphic functions , handles inheritance , and
* returns the funcid and type and set or singleton status of the
@ -334,7 +340,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
}
/*
* So far so good , so do some routine - type - specific processing .
* So far so good , so do some fdresult - type - specific processing .
*/
if ( fdresult = = FUNCDETAIL_NORMAL | | fdresult = = FUNCDETAIL_PROCEDURE )
{
@ -524,30 +530,55 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
actual_arg_types [ 0 ] , rettype , - 1 ,
COERCION_EXPLICIT , COERCE_EXPLICIT_CALL , location ) ;
}
else if ( fdresult = = FUNCDETAIL_MULTIPLE )
{
/*
* We found multiple possible functional matches . If we are dealing
* with attribute notation , return failure , letting the caller report
* " no such column " ( we already determined there wasn ' t one ) . If
* dealing with function notation , report " ambiguous function " ,
* regardless of whether there ' s also a column by this name .
*/
if ( is_column )
return NULL ;
ereport ( ERROR ,
( errcode ( ERRCODE_AMBIGUOUS_FUNCTION ) ,
errmsg ( " function %s is not unique " ,
func_signature_string ( funcname , nargs , argnames ,
actual_arg_types ) ) ,
errhint ( " Could not choose a best candidate function. "
" You might need to add explicit type casts. " ) ,
parser_errposition ( pstate , location ) ) ) ;
}
else
{
/*
* Oops . Time to die .
*
* If we are dealing with the attribute notation rel . function , let the
* caller handle failure .
* Not found as a function . If we are dealing with attribute
* notation , return failure , letting the caller report " no such
* column " (we already determined there wasn't one).
*/
if ( is_column )
return NULL ;
/*
* Else generate a detailed complaint for a function
* Check for column projection interpretation , since we didn ' t before .
*/
if ( fdresult = = FUNCDETAIL_MULTIPLE )
ereport ( ERROR ,
( errcode ( ERRCODE_AMBIGUOUS_FUNCTION ) ,
errmsg ( " function %s is not unique " ,
func_signature_string ( funcname , nargs , argnames ,
actual_arg_types ) ) ,
errhint ( " Could not choose a best candidate function. "
" You might need to add explicit type casts. " ) ,
parser_errposition ( pstate , location ) ) ) ;
else if ( list_length ( agg_order ) > 1 & & ! agg_within_group )
if ( could_be_projection )
{
retval = ParseComplexProjection ( pstate ,
strVal ( linitial ( funcname ) ) ,
first_arg ,
location ) ;
if ( retval )
return retval ;
}
/*
* No function , and no column either . Since we ' re dealing with
* function notation , report " function does not exist " .
*/
if ( list_length ( agg_order ) > 1 & & ! agg_within_group )
{
/* It's agg(x, ORDER BY y,z) ... perhaps misplaced ORDER BY */
ereport ( ERROR ,