diff --git a/doc/src/sgml/ref/alter_extension.sgml b/doc/src/sgml/ref/alter_extension.sgml
index de6d6dca16b..a7c0927d1c9 100644
--- a/doc/src/sgml/ref/alter_extension.sgml
+++ b/doc/src/sgml/ref/alter_extension.sgml
@@ -39,7 +39,7 @@ ALTER EXTENSION name DROP object_name |
FOREIGN DATA WRAPPER object_name |
FOREIGN TABLE object_name |
- FUNCTION function_name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) |
+ FUNCTION function_name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] |
MATERIALIZED VIEW object_name |
OPERATOR operator_name (left_type, right_type) |
OPERATOR CLASS object_name USING index_method |
diff --git a/doc/src/sgml/ref/alter_function.sgml b/doc/src/sgml/ref/alter_function.sgml
index 0388d06b959..168eeb7c526 100644
--- a/doc/src/sgml/ref/alter_function.sgml
+++ b/doc/src/sgml/ref/alter_function.sgml
@@ -21,15 +21,15 @@ PostgreSQL documentation
-ALTER FUNCTION name ( [ [ argmode ] [ argname ] argtype [, ...] ] )
+ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ]
action [ ... ] [ RESTRICT ]
-ALTER FUNCTION name ( [ [ argmode ] [ argname ] argtype [, ...] ] )
+ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ]
RENAME TO new_name
-ALTER FUNCTION name ( [ [ argmode ] [ argname ] argtype [, ...] ] )
+ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ]
OWNER TO { new_owner | CURRENT_USER | SESSION_USER }
-ALTER FUNCTION name ( [ [ argmode ] [ argname ] argtype [, ...] ] )
+ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ]
SET SCHEMA new_schema
-ALTER FUNCTION name ( [ [ argmode ] [ argname ] argtype [, ...] ] )
+ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ]
DEPENDS ON EXTENSION extension_name
where action is one of:
@@ -75,7 +75,8 @@ ALTER FUNCTION name ( [ [ name
- The name (optionally schema-qualified) of an existing function.
+ The name (optionally schema-qualified) of an existing function. If no
+ argument list is specified, the name must be unique in its schema.
diff --git a/doc/src/sgml/ref/alter_opfamily.sgml b/doc/src/sgml/ref/alter_opfamily.sgml
index 4511c7f7b24..0bafe5b8f80 100644
--- a/doc/src/sgml/ref/alter_opfamily.sgml
+++ b/doc/src/sgml/ref/alter_opfamily.sgml
@@ -25,7 +25,7 @@ ALTER OPERATOR FAMILY name USING strategy_number operator_name ( op_type, op_type )
[ FOR SEARCH | FOR ORDER BY sort_family_name ]
| FUNCTION support_number [ ( op_type [ , op_type ] ) ]
- function_name ( argument_type [, ...] )
+ function_name [ ( argument_type [, ...] ) ]
} [, ... ]
ALTER OPERATOR FAMILY name USING index_method DROP
@@ -195,8 +195,9 @@ ALTER OPERATOR FAMILY name USING function_name
- The name (optionally schema-qualified) of a function that is an
- index method support procedure for the operator family.
+ The name (optionally schema-qualified) of a function that is an index
+ method support procedure for the operator family. If no argument list
+ is specified, the name must be unique in its schema.
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index c1cf587cb29..7483c8c03fc 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -37,7 +37,7 @@ COMMENT ON
EVENT TRIGGER object_name |
FOREIGN DATA WRAPPER object_name |
FOREIGN TABLE object_name |
- FUNCTION function_name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) |
+ FUNCTION function_name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] |
INDEX object_name |
LARGE OBJECT large_object_oid |
MATERIALIZED VIEW object_name |
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml
index 11266755e56..a7d13edc22b 100644
--- a/doc/src/sgml/ref/create_cast.sgml
+++ b/doc/src/sgml/ref/create_cast.sgml
@@ -19,7 +19,7 @@
CREATE CAST (source_type AS target_type)
- WITH FUNCTION function_name (argument_type [, ...])
+ WITH FUNCTION function_name [ (argument_type [, ...]) ]
[ AS ASSIGNMENT | AS IMPLICIT ]
CREATE CAST (source_type AS target_type)
@@ -192,7 +192,7 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
- function_name(argument_type [, ...])
+ function_name[(argument_type [, ...])]
@@ -200,6 +200,8 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
be schema-qualified. If it is not, the function will be looked
up in the schema search path. The function's result data type must
match the target type of the cast. Its arguments are discussed below.
+ If no argument list is specified, the function name must be unique in
+ its schema.
diff --git a/doc/src/sgml/ref/create_transform.sgml b/doc/src/sgml/ref/create_transform.sgml
index f44ee89d33c..647c3b9f057 100644
--- a/doc/src/sgml/ref/create_transform.sgml
+++ b/doc/src/sgml/ref/create_transform.sgml
@@ -19,8 +19,8 @@
CREATE [ OR REPLACE ] TRANSFORM FOR type_name LANGUAGE lang_name (
- FROM SQL WITH FUNCTION from_sql_function_name (argument_type [, ...]),
- TO SQL WITH FUNCTION to_sql_function_name (argument_type [, ...])
+ FROM SQL WITH FUNCTION from_sql_function_name [ (argument_type [, ...]) ],
+ TO SQL WITH FUNCTION to_sql_function_name [ (argument_type [, ...]) ]
);
@@ -104,7 +104,7 @@ CREATE [ OR REPLACE ] TRANSFORM FOR type_name LANGUAG
- from_sql_function_name(argument_type [, ...])
+ from_sql_function_name[(argument_type [, ...])]
@@ -116,12 +116,14 @@ CREATE [ OR REPLACE ] TRANSFORM FOR type_name LANGUAG
SQL-level function returning internal without at
least one argument of type internal.) The actual return
value will be something specific to the language implementation.
+ If no argument list is specified, the function name must be unique in
+ its schema.
- to_sql_function_name(argument_type [, ...])
+ to_sql_function_name[(argument_type [, ...])]
@@ -130,6 +132,8 @@ CREATE [ OR REPLACE ] TRANSFORM FOR type_name LANGUAG
internal and return the type that is the type for the
transform. The actual argument value will be something specific to the
language implementation.
+ If no argument list is specified, the function name must be unique in
+ its schema.
diff --git a/doc/src/sgml/ref/drop_function.sgml b/doc/src/sgml/ref/drop_function.sgml
index 5969b084b44..0aa984528d3 100644
--- a/doc/src/sgml/ref/drop_function.sgml
+++ b/doc/src/sgml/ref/drop_function.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
-DROP FUNCTION [ IF EXISTS ] name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) [, ...]
+DROP FUNCTION [ IF EXISTS ] name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] [, ...]
[ CASCADE | RESTRICT ]
@@ -56,7 +56,8 @@ DROP FUNCTION [ IF EXISTS ] name (
name
- The name (optionally schema-qualified) of an existing function.
+ The name (optionally schema-qualified) of an existing function. If no
+ argument list is specified, the name must be unique in its schema.
@@ -141,14 +142,40 @@ DROP FUNCTION sqrt(integer);
DROP FUNCTION sqrt(integer), sqrt(bigint);
+
+
+ If the function name is unique in its schema, it can be referred to without
+ an argument list:
+
+DROP FUNCTION update_employee_salaries;
+
+ Note that this is different from
+
+DROP FUNCTION update_employee_salaries();
+
+ which refers to a function with zero arguments, whereas the first variant
+ can refer to a function with any number of arguments, including zero, as
+ long as the name is unique.
+
Compatibility
- A DROP FUNCTION statement is defined in the SQL
- standard, but it is not compatible with this command.
+ This command conforms to the SQL standard, with
+ these PostgreSQL extensions:
+
+
+ The standard only allows one function to be dropped per command.
+
+
+ The IF EXISTS option
+
+
+ The ability to specify argument modes and names
+
+
diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index d8ca39f869e..9fb4c2fd7e3 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -55,7 +55,7 @@ GRANT { USAGE | ALL [ PRIVILEGES ] }
TO role_specification [, ...] [ WITH GRANT OPTION ]
GRANT { EXECUTE | ALL [ PRIVILEGES ] }
- ON { FUNCTION function_name ( [ [ argmode ] [ arg_name ] arg_type [, ...] ] ) [, ...]
+ ON { FUNCTION function_name [ ( [ [ argmode ] [ arg_name ] arg_type [, ...] ] ) ] [, ...]
| ALL FUNCTIONS IN SCHEMA schema_name [, ...] }
TO role_specification [, ...] [ WITH GRANT OPTION ]
diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml
index fc00129620b..ce532543f0b 100644
--- a/doc/src/sgml/ref/revoke.sgml
+++ b/doc/src/sgml/ref/revoke.sgml
@@ -70,7 +70,7 @@ REVOKE [ GRANT OPTION FOR ]
REVOKE [ GRANT OPTION FOR ]
{ EXECUTE | ALL [ PRIVILEGES ] }
- ON { FUNCTION function_name ( [ [ argmode ] [ arg_name ] arg_type [, ...] ] ) [, ...]
+ ON { FUNCTION function_name [ ( [ [ argmode ] [ arg_name ] arg_type [, ...] ] ) ] [, ...]
| ALL FUNCTIONS IN SCHEMA schema_name [, ...] }
FROM { [ GROUP ] role_name | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
diff --git a/doc/src/sgml/ref/security_label.sgml b/doc/src/sgml/ref/security_label.sgml
index 998fe3b7c03..afd86aff3a0 100644
--- a/doc/src/sgml/ref/security_label.sgml
+++ b/doc/src/sgml/ref/security_label.sgml
@@ -30,7 +30,7 @@ SECURITY LABEL [ FOR provider ] ON
DOMAIN object_name |
EVENT TRIGGER object_name |
FOREIGN TABLE object_name
- FUNCTION function_name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) |
+ FUNCTION function_name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] |
LARGE OBJECT large_object_oid |
MATERIALIZED VIEW object_name |
[ PROCEDURAL ] LANGUAGE object_name |
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bfc2ac17165..25fd051d6ef 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3067,6 +3067,7 @@ _copyObjectWithArgs(const ObjectWithArgs *from)
COPY_NODE_FIELD(objname);
COPY_NODE_FIELD(objargs);
+ COPY_SCALAR_FIELD(args_unspecified);
return newnode;
}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 54e9c983a0f..67529e3f861 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1119,6 +1119,7 @@ _equalObjectWithArgs(const ObjectWithArgs *a, const ObjectWithArgs *b)
{
COMPARE_NODE_FIELD(objname);
COMPARE_NODE_FIELD(objargs);
+ COMPARE_SCALAR_FIELD(args_unspecified);
return true;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e7acc2d9a23..6316688a883 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -7202,6 +7202,33 @@ function_with_argtypes:
n->objargs = extractArgTypes($2);
$$ = n;
}
+ /*
+ * Because of reduce/reduce conflicts, we can't use func_name
+ * below, but we can write it out the long way, which actually
+ * allows more cases.
+ */
+ | type_func_name_keyword
+ {
+ ObjectWithArgs *n = makeNode(ObjectWithArgs);
+ n->objname = list_make1(makeString(pstrdup($1)));
+ n->args_unspecified = true;
+ $$ = n;
+ }
+ | ColId
+ {
+ ObjectWithArgs *n = makeNode(ObjectWithArgs);
+ n->objname = list_make1(makeString($1));
+ n->args_unspecified = true;
+ $$ = n;
+ }
+ | ColId indirection
+ {
+ ObjectWithArgs *n = makeNode(ObjectWithArgs);
+ n->objname = check_func_name(lcons(makeString($1), $2),
+ yyscanner);
+ n->args_unspecified = true;
+ $$ = n;
+ }
;
/*
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index dd9749f2056..55853c20bb4 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -1895,8 +1895,10 @@ func_signature_string(List *funcname, int nargs,
/*
* LookupFuncName
- * Given a possibly-qualified function name and a set of argument types,
- * look up the function.
+ *
+ * Given a possibly-qualified function name and optionally a set of argument
+ * types, look up the function. Pass nargs == -1 to indicate that no argument
+ * types are specified.
*
* If the function name is not schema-qualified, it is sought in the current
* namespace search path.
@@ -1914,6 +1916,35 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false, noError);
+ /*
+ * If no arguments were specified, the name must yield a unique candidate.
+ */
+ if (nargs == -1)
+ {
+ if (clist)
+ {
+ if (clist->next)
+ {
+ if (!noError)
+ ereport(ERROR,
+ (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+ errmsg("function name \"%s\" is not unique",
+ NameListToString(funcname)),
+ errhint("Specify the argument list to select the function unambiguously.")));
+ }
+ else
+ return clist->oid;
+ }
+ else
+ {
+ if (!noError)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not find a function named \"%s\"",
+ NameListToString(funcname))));
+ }
+ }
+
while (clist)
{
if (memcmp(argtypes, clist->args, nargs * sizeof(Oid)) == 0)
@@ -1962,7 +1993,7 @@ LookupFuncWithArgs(ObjectWithArgs *func, bool noError)
args_item = lnext(args_item);
}
- return LookupFuncName(func->objname, argcount, argoids, noError);
+ return LookupFuncName(func->objname, func->args_unspecified ? -1 : argcount, argoids, noError);
}
/*
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index a44d2178e1c..d576523f6a8 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1811,6 +1811,9 @@ typedef struct ObjectWithArgs
NodeTag type;
List *objname; /* qualified name of function/operator */
List *objargs; /* list of Typename nodes */
+ bool args_unspecified; /* argument list was omitted, so name must
+ * be unique (note that objargs == NIL means
+ * zero args) */
} ObjectWithArgs;
/*
diff --git a/src/test/regress/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out
index cc4e98a1d4b..b5e19485e56 100644
--- a/src/test/regress/expected/create_function_3.out
+++ b/src/test/regress/expected/create_function_3.out
@@ -218,13 +218,21 @@ SELECT routine_name, ordinal_position, parameter_name, parameter_default
(7 rows)
DROP FUNCTION functest_IS_1(int, int, text), functest_IS_2(int), functest_IS_3(int);
+-- overload
+CREATE FUNCTION functest_B_2(bigint) RETURNS bool LANGUAGE 'sql'
+ IMMUTABLE AS 'SELECT $1 > 0';
+DROP FUNCTION functest_b_1;
+DROP FUNCTION functest_b_1; -- error, not found
+ERROR: could not find a function named "functest_b_1"
+DROP FUNCTION functest_b_2; -- error, ambiguous
+ERROR: function name "functest_b_2" is not unique
+HINT: Specify the argument list to select the function unambiguously.
-- Cleanups
DROP SCHEMA temp_func_test CASCADE;
NOTICE: drop cascades to 16 other objects
DETAIL: drop cascades to function functest_a_1(text,date)
drop cascades to function functest_a_2(text[])
drop cascades to function functest_a_3()
-drop cascades to function functest_b_1(integer)
drop cascades to function functest_b_2(integer)
drop cascades to function functest_b_3(integer)
drop cascades to function functest_b_4(integer)
@@ -237,5 +245,6 @@ drop cascades to function functext_f_1(integer)
drop cascades to function functext_f_2(integer)
drop cascades to function functext_f_3(integer)
drop cascades to function functext_f_4(integer)
+drop cascades to function functest_b_2(bigint)
DROP USER regress_unpriv_user;
RESET search_path;
diff --git a/src/test/regress/sql/create_function_3.sql b/src/test/regress/sql/create_function_3.sql
index 66a463b0895..0a0e407aaba 100644
--- a/src/test/regress/sql/create_function_3.sql
+++ b/src/test/regress/sql/create_function_3.sql
@@ -158,6 +158,14 @@ SELECT routine_name, ordinal_position, parameter_name, parameter_default
DROP FUNCTION functest_IS_1(int, int, text), functest_IS_2(int), functest_IS_3(int);
+-- overload
+CREATE FUNCTION functest_B_2(bigint) RETURNS bool LANGUAGE 'sql'
+ IMMUTABLE AS 'SELECT $1 > 0';
+
+DROP FUNCTION functest_b_1;
+DROP FUNCTION functest_b_1; -- error, not found
+DROP FUNCTION functest_b_2; -- error, ambiguous
+
-- Cleanups
DROP SCHEMA temp_func_test CASCADE;