diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index d43b89d3ef..6fc3863265 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -232,7 +232,7 @@ interpret_function_parameter_list(ParseState *pstate, if (fpmode == FUNC_PARAM_DEFAULT) fpmode = FUNC_PARAM_IN; - typtup = LookupTypeName(NULL, t, NULL, false); + typtup = LookupTypeName(pstate, t, NULL, false); if (typtup) { if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined) @@ -242,18 +242,21 @@ interpret_function_parameter_list(ParseState *pstate, ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SQL function cannot accept shell type %s", - TypeNameToString(t)))); + TypeNameToString(t)), + parser_errposition(pstate, t->location))); /* We don't allow creating aggregates on shell types either */ else if (objtype == OBJECT_AGGREGATE) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("aggregate cannot accept shell type %s", - TypeNameToString(t)))); + TypeNameToString(t)), + parser_errposition(pstate, t->location))); else ereport(NOTICE, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("argument type %s is only a shell", - TypeNameToString(t)))); + TypeNameToString(t)), + parser_errposition(pstate, t->location))); } toid = typeTypeId(typtup); ReleaseSysCache(typtup); @@ -263,7 +266,8 @@ interpret_function_parameter_list(ParseState *pstate, ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type %s does not exist", - TypeNameToString(t)))); + TypeNameToString(t)), + parser_errposition(pstate, t->location))); toid = InvalidOid; /* keep compiler quiet */ } @@ -276,15 +280,18 @@ interpret_function_parameter_list(ParseState *pstate, if (objtype == OBJECT_AGGREGATE) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("aggregates cannot accept set arguments"))); + errmsg("aggregates cannot accept set arguments"), + parser_errposition(pstate, fp->location))); else if (objtype == OBJECT_PROCEDURE) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("procedures cannot accept set arguments"))); + errmsg("procedures cannot accept set arguments"), + parser_errposition(pstate, fp->location))); else ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("functions cannot accept set arguments"))); + errmsg("functions cannot accept set arguments"), + parser_errposition(pstate, fp->location))); } /* handle input parameters */ @@ -294,7 +301,8 @@ interpret_function_parameter_list(ParseState *pstate, if (varCount > 0) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("VARIADIC parameter must be the last input parameter"))); + errmsg("VARIADIC parameter must be the last input parameter"), + parser_errposition(pstate, fp->location))); inTypes[inCount++] = toid; isinput = true; if (parameterTypes_list) @@ -314,7 +322,8 @@ interpret_function_parameter_list(ParseState *pstate, if (varCount > 0) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("VARIADIC parameter must be the last parameter"))); + errmsg("VARIADIC parameter must be the last parameter"), + parser_errposition(pstate, fp->location))); /* Procedures with output parameters always return RECORD */ *requiredResultType = RECORDOID; } @@ -339,7 +348,8 @@ interpret_function_parameter_list(ParseState *pstate, if (!OidIsValid(get_element_type(toid))) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("VARIADIC parameter must be an array"))); + errmsg("VARIADIC parameter must be an array"), + parser_errposition(pstate, fp->location))); break; } } @@ -385,7 +395,8 @@ interpret_function_parameter_list(ParseState *pstate, ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("parameter name \"%s\" used more than once", - fp->name))); + fp->name), + parser_errposition(pstate, fp->location))); } paramNames[i] = CStringGetTextDatum(fp->name); @@ -402,7 +413,8 @@ interpret_function_parameter_list(ParseState *pstate, if (!isinput) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("only input parameters can have default values"))); + errmsg("only input parameters can have default values"), + parser_errposition(pstate, fp->location))); def = transformExpr(pstate, fp->defexpr, EXPR_KIND_FUNCTION_DEFAULT); @@ -417,7 +429,8 @@ interpret_function_parameter_list(ParseState *pstate, contain_var_clause(def)) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), - errmsg("cannot use table references in parameter default value"))); + errmsg("cannot use table references in parameter default value"), + parser_errposition(pstate, fp->location))); /* * transformExpr() should have already rejected subqueries, @@ -441,7 +454,8 @@ interpret_function_parameter_list(ParseState *pstate, if (isinput && have_defaults) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("input parameters after one with a default value must also have defaults"))); + errmsg("input parameters after one with a default value must also have defaults"), + parser_errposition(pstate, fp->location))); /* * For procedures, we also can't allow OUT parameters after one @@ -451,7 +465,8 @@ interpret_function_parameter_list(ParseState *pstate, if (objtype == OBJECT_PROCEDURE && have_defaults) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("procedure OUT parameters cannot appear after one with a default value"))); + errmsg("procedure OUT parameters cannot appear after one with a default value"), + parser_errposition(pstate, fp->location))); } i++; diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index f76072228c..3060847b13 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -1723,8 +1723,7 @@ exprLocation(const Node *expr) loc = ((const Constraint *) expr)->location; break; case T_FunctionParameter: - /* just use typename's location */ - loc = exprLocation((Node *) ((const FunctionParameter *) expr)->argType); + loc = ((const FunctionParameter *) expr)->location; break; case T_XmlSerialize: /* XMLSERIALIZE keyword should always be the first thing */ diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index dd458182f0..c96505f8b4 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -184,7 +184,7 @@ static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location); static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, int location); -static List *mergeTableFuncParameters(List *func_args, List *columns); +static List *mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner); static TypeName *TableFuncTypeName(List *columns); static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner); static RangeVar *makeRangeVarFromQualifiedName(char *name, List *namelist, int location, @@ -8290,7 +8290,7 @@ CreateFunctionStmt: n->is_procedure = false; n->replace = $2; n->funcname = $4; - n->parameters = mergeTableFuncParameters($5, $9); + n->parameters = mergeTableFuncParameters($5, $9, yyscanner); n->returnType = TableFuncTypeName($9); n->returnType->location = @7; n->options = $11; @@ -8423,6 +8423,7 @@ func_arg: n->argType = $3; n->mode = $1; n->defexpr = NULL; + n->location = @1; $$ = n; } | param_name arg_class func_type @@ -8433,6 +8434,7 @@ func_arg: n->argType = $3; n->mode = $2; n->defexpr = NULL; + n->location = @1; $$ = n; } | param_name func_type @@ -8443,6 +8445,7 @@ func_arg: n->argType = $2; n->mode = FUNC_PARAM_DEFAULT; n->defexpr = NULL; + n->location = @1; $$ = n; } | arg_class func_type @@ -8453,6 +8456,7 @@ func_arg: n->argType = $2; n->mode = $1; n->defexpr = NULL; + n->location = @1; $$ = n; } | func_type @@ -8463,6 +8467,7 @@ func_arg: n->argType = $1; n->mode = FUNC_PARAM_DEFAULT; n->defexpr = NULL; + n->location = @1; $$ = n; } ; @@ -8799,6 +8804,7 @@ table_func_column: param_name func_type n->argType = $2; n->mode = FUNC_PARAM_TABLE; n->defexpr = NULL; + n->location = @1; $$ = n; } ; @@ -18908,7 +18914,7 @@ makeOrderedSetArgs(List *directargs, List *orderedargs, ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("an ordered-set aggregate with a VARIADIC direct argument must have one VARIADIC aggregated argument of the same data type"), - parser_errposition(exprLocation((Node *) firsto)))); + parser_errposition(firsto->location))); /* OK, drop the duplicate VARIADIC argument from the internal form */ orderedargs = NIL; @@ -19183,7 +19189,7 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, * Merge the input and output parameters of a table function. */ static List * -mergeTableFuncParameters(List *func_args, List *columns) +mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner) { ListCell *lc; @@ -19197,7 +19203,8 @@ mergeTableFuncParameters(List *func_args, List *columns) p->mode != FUNC_PARAM_VARIADIC) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("OUT and INOUT arguments aren't allowed in TABLE functions"))); + errmsg("OUT and INOUT arguments aren't allowed in TABLE functions"), + parser_errposition(p->location))); } return list_concat(func_args, columns); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index fc1c125d0d..0fc51a2160 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202410242 +#define CATALOG_VERSION_NO 202410311 #endif diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index b40b661ec8..0d96db5638 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -3482,6 +3482,7 @@ typedef struct FunctionParameter TypeName *argType; /* TypeName for parameter type */ FunctionParameterMode mode; /* IN/OUT/etc */ Node *defexpr; /* raw default expr, or NULL if not given */ + ParseLoc location; /* token location, or -1 if unknown */ } FunctionParameter; typedef struct AlterFunctionStmt diff --git a/src/test/modules/test_ddl_deparse/expected/create_type.out b/src/test/modules/test_ddl_deparse/expected/create_type.out index dadbc8f7f0..b754455e2b 100644 --- a/src/test/modules/test_ddl_deparse/expected/create_type.out +++ b/src/test/modules/test_ddl_deparse/expected/create_type.out @@ -13,6 +13,8 @@ CREATE FUNCTION text_w_default_out(text_w_default) AS 'textout' LANGUAGE internal STABLE STRICT ; NOTICE: argument type text_w_default is only a shell +LINE 1: CREATE FUNCTION text_w_default_out(text_w_default) + ^ NOTICE: DDL test: type simple, tag CREATE FUNCTION CREATE TYPE employee_type AS (name TEXT, salary NUMERIC); NOTICE: DDL test: type simple, tag CREATE TYPE diff --git a/src/test/modules/test_ddl_deparse/expected/opfamily.out b/src/test/modules/test_ddl_deparse/expected/opfamily.out index c7e3a23ef7..4e1cc747cb 100644 --- a/src/test/modules/test_ddl_deparse/expected/opfamily.out +++ b/src/test/modules/test_ddl_deparse/expected/opfamily.out @@ -8,6 +8,8 @@ NOTICE: DDL test: type simple, tag CREATE FUNCTION create function int8alias1out(int8alias1) returns cstring strict immutable language internal as 'int8out'; NOTICE: argument type int8alias1 is only a shell +LINE 1: create function int8alias1out(int8alias1) returns cstring + ^ NOTICE: DDL test: type simple, tag CREATE FUNCTION create type int8alias1 ( input = int8alias1in, @@ -24,6 +26,8 @@ NOTICE: DDL test: type simple, tag CREATE FUNCTION create function int8alias2out(int8alias2) returns cstring strict immutable language internal as 'int8out'; NOTICE: argument type int8alias2 is only a shell +LINE 1: create function int8alias2out(int8alias2) returns cstring + ^ NOTICE: DDL test: type simple, tag CREATE FUNCTION create type int8alias2 ( input = int8alias2in, diff --git a/src/test/modules/test_pg_dump/expected/test_pg_dump.out b/src/test/modules/test_pg_dump/expected/test_pg_dump.out index 3536d636d8..98c9cd481e 100644 --- a/src/test/modules/test_pg_dump/expected/test_pg_dump.out +++ b/src/test/modules/test_pg_dump/expected/test_pg_dump.out @@ -36,6 +36,8 @@ CREATE FUNCTION casttesttype_out(casttesttype) AS 'textout' LANGUAGE internal STRICT IMMUTABLE; NOTICE: argument type casttesttype is only a shell +LINE 1: CREATE FUNCTION casttesttype_out(casttesttype) + ^ CREATE TYPE casttesttype ( internallength = variable, input = casttesttype_in, diff --git a/src/test/regress/expected/create_cast.out b/src/test/regress/expected/create_cast.out index 9a56fe3f0f..fd4871d94d 100644 --- a/src/test/regress/expected/create_cast.out +++ b/src/test/regress/expected/create_cast.out @@ -13,6 +13,8 @@ CREATE FUNCTION casttesttype_out(casttesttype) AS 'textout' LANGUAGE internal STRICT IMMUTABLE; NOTICE: argument type casttesttype is only a shell +LINE 1: CREATE FUNCTION casttesttype_out(casttesttype) + ^ CREATE TYPE casttesttype ( internallength = variable, input = casttesttype_in, diff --git a/src/test/regress/expected/create_procedure.out b/src/test/regress/expected/create_procedure.out index 2177ba3509..45b402e25e 100644 --- a/src/test/regress/expected/create_procedure.out +++ b/src/test/regress/expected/create_procedure.out @@ -401,9 +401,13 @@ LINE 1: CREATE PROCEDURE ptestx() LANGUAGE SQL STRICT AS $$ INSERT I... CREATE PROCEDURE ptestx(a VARIADIC int[], b OUT int) LANGUAGE SQL AS $$ SELECT a[1] $$; ERROR: VARIADIC parameter must be the last parameter +LINE 1: CREATE PROCEDURE ptestx(a VARIADIC int[], b OUT int) LANGUAG... + ^ CREATE PROCEDURE ptestx(a int DEFAULT 42, b OUT int) LANGUAGE SQL AS $$ SELECT a $$; ERROR: procedure OUT parameters cannot appear after one with a default value +LINE 1: CREATE PROCEDURE ptestx(a int DEFAULT 42, b OUT int) LANGUAG... + ^ ALTER PROCEDURE ptest1(text) STRICT; ERROR: invalid attribute in procedure definition LINE 1: ALTER PROCEDURE ptest1(text) STRICT; diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out index 7383fcdbb1..5181c4290b 100644 --- a/src/test/regress/expected/create_type.out +++ b/src/test/regress/expected/create_type.out @@ -20,6 +20,8 @@ CREATE FUNCTION widget_out(widget) AS :'regresslib' LANGUAGE C STRICT IMMUTABLE; NOTICE: argument type widget is only a shell +LINE 1: CREATE FUNCTION widget_out(widget) + ^ CREATE FUNCTION int44in(cstring) RETURNS city_budget AS :'regresslib' @@ -31,6 +33,8 @@ CREATE FUNCTION int44out(city_budget) AS :'regresslib' LANGUAGE C STRICT IMMUTABLE; NOTICE: argument type city_budget is only a shell +LINE 1: CREATE FUNCTION int44out(city_budget) + ^ CREATE TYPE widget ( internallength = 24, input = widget_in, @@ -75,6 +79,8 @@ CREATE FUNCTION int42_out(int42) AS 'int4out' LANGUAGE internal STRICT IMMUTABLE; NOTICE: argument type int42 is only a shell +LINE 1: CREATE FUNCTION int42_out(int42) + ^ CREATE FUNCTION text_w_default_in(cstring) RETURNS text_w_default AS 'textin' @@ -85,6 +91,8 @@ CREATE FUNCTION text_w_default_out(text_w_default) AS 'textout' LANGUAGE internal STRICT IMMUTABLE; NOTICE: argument type text_w_default is only a shell +LINE 1: CREATE FUNCTION text_w_default_out(text_w_default) + ^ CREATE TYPE int42 ( internallength = 4, input = int42_in, @@ -186,6 +194,8 @@ NOTICE: return type base_type is only a shell CREATE FUNCTION base_fn_out(base_type) RETURNS cstring AS 'boolout' LANGUAGE internal IMMUTABLE STRICT; NOTICE: argument type base_type is only a shell +LINE 1: CREATE FUNCTION base_fn_out(base_type) RETURNS cstring AS 'b... + ^ CREATE TYPE base_type(INPUT = base_fn_in, OUTPUT = base_fn_out); DROP FUNCTION base_fn_in(cstring); -- error ERROR: cannot drop function base_fn_in(cstring) because other objects depend on it @@ -320,9 +330,13 @@ NOTICE: return type myvarchar is only a shell CREATE FUNCTION myvarcharout(myvarchar) RETURNS cstring LANGUAGE internal IMMUTABLE PARALLEL SAFE STRICT AS 'varcharout'; NOTICE: argument type myvarchar is only a shell +LINE 1: CREATE FUNCTION myvarcharout(myvarchar) RETURNS cstring + ^ CREATE FUNCTION myvarcharsend(myvarchar) RETURNS bytea LANGUAGE internal STABLE PARALLEL SAFE STRICT AS 'varcharsend'; NOTICE: argument type myvarchar is only a shell +LINE 1: CREATE FUNCTION myvarcharsend(myvarchar) RETURNS bytea + ^ CREATE FUNCTION myvarcharrecv(internal, oid, integer) RETURNS myvarchar LANGUAGE internal STABLE PARALLEL SAFE STRICT AS 'varcharrecv'; NOTICE: return type myvarchar is only a shell diff --git a/src/test/regress/expected/equivclass.out b/src/test/regress/expected/equivclass.out index a328164fe0..5622750500 100644 --- a/src/test/regress/expected/equivclass.out +++ b/src/test/regress/expected/equivclass.out @@ -16,6 +16,8 @@ NOTICE: return type int8alias1 is only a shell create function int8alias1out(int8alias1) returns cstring strict immutable language internal as 'int8out'; NOTICE: argument type int8alias1 is only a shell +LINE 1: create function int8alias1out(int8alias1) returns cstring + ^ create type int8alias1 ( input = int8alias1in, output = int8alias1out, @@ -28,6 +30,8 @@ NOTICE: return type int8alias2 is only a shell create function int8alias2out(int8alias2) returns cstring strict immutable language internal as 'int8out'; NOTICE: argument type int8alias2 is only a shell +LINE 1: create function int8alias2out(int8alias2) returns cstring + ^ create type int8alias2 ( input = int8alias2in, output = int8alias2out, diff --git a/src/test/regress/expected/expressions.out b/src/test/regress/expected/expressions.out index caeeb19674..21c54fc198 100644 --- a/src/test/regress/expected/expressions.out +++ b/src/test/regress/expected/expressions.out @@ -337,9 +337,13 @@ NOTICE: return type myint is only a shell create function myintout(myint) returns cstring strict immutable language internal as 'int4out'; NOTICE: argument type myint is only a shell +LINE 1: create function myintout(myint) returns cstring strict immut... + ^ create function myinthash(myint) returns integer strict immutable language internal as 'hashint4'; NOTICE: argument type myint is only a shell +LINE 1: create function myinthash(myint) returns integer strict immu... + ^ create type myint (input = myintin, output = myintout, like = int4); create cast (int4 as myint) without function; create cast (myint as int4) without function; diff --git a/src/test/regress/expected/float4-misrounded-input.out b/src/test/regress/expected/float4-misrounded-input.out index a427231627..20fd713913 100644 --- a/src/test/regress/expected/float4-misrounded-input.out +++ b/src/test/regress/expected/float4-misrounded-input.out @@ -490,6 +490,8 @@ NOTICE: return type xfloat4 is only a shell create function xfloat4out(xfloat4) returns cstring immutable strict language internal as 'int4out'; NOTICE: argument type xfloat4 is only a shell +LINE 1: create function xfloat4out(xfloat4) returns cstring immutabl... + ^ create type xfloat4 (input = xfloat4in, output = xfloat4out, like = float4); create cast (xfloat4 as float4) without function; create cast (float4 as xfloat4) without function; diff --git a/src/test/regress/expected/float4.out b/src/test/regress/expected/float4.out index 65ee82caae..1d21c4390a 100644 --- a/src/test/regress/expected/float4.out +++ b/src/test/regress/expected/float4.out @@ -490,6 +490,8 @@ NOTICE: return type xfloat4 is only a shell create function xfloat4out(xfloat4) returns cstring immutable strict language internal as 'int4out'; NOTICE: argument type xfloat4 is only a shell +LINE 1: create function xfloat4out(xfloat4) returns cstring immutabl... + ^ create type xfloat4 (input = xfloat4in, output = xfloat4out, like = float4); create cast (xfloat4 as float4) without function; create cast (float4 as xfloat4) without function; diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out index 344d6b7d6d..de56998f5c 100644 --- a/src/test/regress/expected/float8.out +++ b/src/test/regress/expected/float8.out @@ -1022,6 +1022,8 @@ NOTICE: return type xfloat8 is only a shell create function xfloat8out(xfloat8) returns cstring immutable strict language internal as 'int8out'; NOTICE: argument type xfloat8 is only a shell +LINE 1: create function xfloat8out(xfloat8) returns cstring immutabl... + ^ create type xfloat8 (input = xfloat8in, output = xfloat8out, like = float8); create cast (xfloat8 as float8) without function; create cast (float8 as xfloat8) without function; diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out index bf08e40ed8..94eedfe375 100644 --- a/src/test/regress/expected/polymorphism.out +++ b/src/test/regress/expected/polymorphism.out @@ -1165,6 +1165,8 @@ create function dfunc(a int = 1, b int) returns int as $$ select $1 + $2; $$ language sql; ERROR: input parameters after one with a default value must also have defaults +LINE 1: create function dfunc(a int = 1, b int) returns int as $$ + ^ -- however, this should work: create function dfunc(a int = 1, out sum int, b int = 2) as $$ select $1 + $2; @@ -1270,6 +1272,8 @@ create function dfunc(out int = 20) returns int as $$ select 1; $$ language sql; ERROR: only input parameters can have default values +LINE 1: create function dfunc(out int = 20) returns int as $$ + ^ -- polymorphic parameter test create function dfunc(anyelement = 'World'::text) returns text as $$ select 'Hello, ' || $1::text; @@ -1567,12 +1571,20 @@ drop function dfunc(varchar, numeric); --fail, named parameters are not unique create function testpolym(a int, a int) returns int as $$ select 1;$$ language sql; ERROR: parameter name "a" used more than once +LINE 1: create function testpolym(a int, a int) returns int as $$ se... + ^ create function testpolym(int, out a int, out a int) returns int as $$ select 1;$$ language sql; ERROR: parameter name "a" used more than once +LINE 1: create function testpolym(int, out a int, out a int) returns... + ^ create function testpolym(out a int, inout a int) returns int as $$ select 1;$$ language sql; ERROR: parameter name "a" used more than once +LINE 1: create function testpolym(out a int, inout a int) returns in... + ^ create function testpolym(a int, inout a int) returns int as $$ select 1;$$ language sql; ERROR: parameter name "a" used more than once +LINE 1: create function testpolym(a int, inout a int) returns int as... + ^ -- valid create function testpolym(a int, out a int) returns int as $$ select $1;$$ language sql; select testpolym(37);