0002-reallow-SQL-drop-syntax.patch
text/x-diff
Filename: 0002-reallow-SQL-drop-syntax.patch
Type: text/x-diff
Part: 1
Patch
Format: unified
Series: patch 0002
| File | + | − |
|---|---|---|
| src/backend/commands/functioncmds.c | 22 | 12 |
| src/backend/nodes/copyfuncs.c | 1 | 0 |
| src/backend/nodes/equalfuncs.c | 1 | 0 |
| src/backend/parser/gram.y | 9 | 4 |
| src/backend/parser/parse_func.c | 149 | 38 |
| src/backend/parser/parse_oper.c | 2 | 2 |
| src/backend/utils/adt/ruleutils.c | 9 | 1 |
| src/bin/pg_dump/t/002_pg_dump.pl | 1 | 1 |
| src/include/nodes/parsenodes.h | 21 | 8 |
| src/test/regress/expected/create_procedure.out | 63 | 25 |
| src/test/regress/sql/create_procedure.sql | 19 | 0 |
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 8572d8543a..736d04780a 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -227,11 +227,16 @@ interpret_function_parameter_list(ParseState *pstate,
{
FunctionParameter *fp = (FunctionParameter *) lfirst(x);
TypeName *t = fp->argType;
+ FunctionParameterMode fpmode = fp->mode;
bool isinput = false;
Oid toid;
Type typtup;
AclResult aclresult;
+ /* For our purposes here, a defaulted mode spec is identical to IN */
+ if (fpmode == FUNC_PARAM_DEFAULT)
+ fpmode = FUNC_PARAM_IN;
+
typtup = LookupTypeName(NULL, t, NULL, false);
if (typtup)
{
@@ -288,7 +293,7 @@ interpret_function_parameter_list(ParseState *pstate,
}
/* handle input parameters */
- if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
+ if (fpmode != FUNC_PARAM_OUT && fpmode != FUNC_PARAM_TABLE)
{
/* other input parameters can't follow a VARIADIC parameter */
if (varCount > 0)
@@ -302,7 +307,7 @@ interpret_function_parameter_list(ParseState *pstate,
}
/* handle output parameters */
- if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
+ if (fpmode != FUNC_PARAM_IN && fpmode != FUNC_PARAM_VARIADIC)
{
if (objtype == OBJECT_PROCEDURE)
{
@@ -323,7 +328,7 @@ interpret_function_parameter_list(ParseState *pstate,
outCount++;
}
- if (fp->mode == FUNC_PARAM_VARIADIC)
+ if (fpmode == FUNC_PARAM_VARIADIC)
{
*variadicArgType = toid;
varCount++;
@@ -346,7 +351,7 @@ interpret_function_parameter_list(ParseState *pstate,
allTypes[i] = ObjectIdGetDatum(toid);
- paramModes[i] = CharGetDatum(fp->mode);
+ paramModes[i] = CharGetDatum(fpmode);
if (fp->name && fp->name[0])
{
@@ -361,19 +366,24 @@ interpret_function_parameter_list(ParseState *pstate,
foreach(px, parameters)
{
FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
+ FunctionParameterMode prevfpmode;
if (prevfp == fp)
break;
+ /* as above, default mode is IN */
+ prevfpmode = prevfp->mode;
+ if (prevfpmode == FUNC_PARAM_DEFAULT)
+ prevfpmode = FUNC_PARAM_IN;
/* pure in doesn't conflict with pure out */
- if ((fp->mode == FUNC_PARAM_IN ||
- fp->mode == FUNC_PARAM_VARIADIC) &&
- (prevfp->mode == FUNC_PARAM_OUT ||
- prevfp->mode == FUNC_PARAM_TABLE))
+ if ((fpmode == FUNC_PARAM_IN ||
+ fpmode == FUNC_PARAM_VARIADIC) &&
+ (prevfpmode == FUNC_PARAM_OUT ||
+ prevfpmode == FUNC_PARAM_TABLE))
continue;
- if ((prevfp->mode == FUNC_PARAM_IN ||
- prevfp->mode == FUNC_PARAM_VARIADIC) &&
- (fp->mode == FUNC_PARAM_OUT ||
- fp->mode == FUNC_PARAM_TABLE))
+ if ((prevfpmode == FUNC_PARAM_IN ||
+ prevfpmode == FUNC_PARAM_VARIADIC) &&
+ (fpmode == FUNC_PARAM_OUT ||
+ fpmode == FUNC_PARAM_TABLE))
continue;
if (prevfp->name && prevfp->name[0] &&
strcmp(prevfp->name, fp->name) == 0)
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 3dd467e0e9..92d541c7fb 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3407,6 +3407,7 @@ _copyObjectWithArgs(const ObjectWithArgs *from)
COPY_NODE_FIELD(objname);
COPY_NODE_FIELD(objargs);
+ COPY_NODE_FIELD(objfuncargs);
COPY_SCALAR_FIELD(args_unspecified);
return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index d38cf55e6d..f772f05c72 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1182,6 +1182,7 @@ _equalObjectWithArgs(const ObjectWithArgs *a, const ObjectWithArgs *b)
{
COMPARE_NODE_FIELD(objname);
COMPARE_NODE_FIELD(objargs);
+ COMPARE_NODE_FIELD(objfuncargs);
COMPARE_SCALAR_FIELD(args_unspecified);
return true;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 2bd09b1575..284f6b1978 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -7562,6 +7562,7 @@ function_with_argtypes:
ObjectWithArgs *n = makeNode(ObjectWithArgs);
n->objname = $1;
n->objargs = extractArgTypes($2);
+ n->objfuncargs = $2;
$$ = n;
}
/*
@@ -7642,7 +7643,7 @@ func_arg:
FunctionParameter *n = makeNode(FunctionParameter);
n->name = $1;
n->argType = $2;
- n->mode = FUNC_PARAM_IN;
+ n->mode = FUNC_PARAM_DEFAULT;
n->defexpr = NULL;
$$ = n;
}
@@ -7660,7 +7661,7 @@ func_arg:
FunctionParameter *n = makeNode(FunctionParameter);
n->name = NULL;
n->argType = $1;
- n->mode = FUNC_PARAM_IN;
+ n->mode = FUNC_PARAM_DEFAULT;
n->defexpr = NULL;
$$ = n;
}
@@ -7732,7 +7733,8 @@ func_arg_with_default:
/* Aggregate args can be most things that function args can be */
aggr_arg: func_arg
{
- if (!($1->mode == FUNC_PARAM_IN ||
+ if (!($1->mode == FUNC_PARAM_DEFAULT ||
+ $1->mode == FUNC_PARAM_IN ||
$1->mode == FUNC_PARAM_VARIADIC))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -7801,6 +7803,7 @@ aggregate_with_argtypes:
ObjectWithArgs *n = makeNode(ObjectWithArgs);
n->objname = $1;
n->objargs = extractAggrArgTypes($2);
+ n->objfuncargs = (List *) linitial($2);
$$ = n;
}
;
@@ -16987,7 +16990,9 @@ mergeTableFuncParameters(List *func_args, List *columns)
{
FunctionParameter *p = (FunctionParameter *) lfirst(lc);
- if (p->mode != FUNC_PARAM_IN && p->mode != FUNC_PARAM_VARIADIC)
+ if (p->mode != FUNC_PARAM_DEFAULT &&
+ p->mode != FUNC_PARAM_IN &&
+ p->mode != FUNC_PARAM_VARIADIC)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("OUT and INOUT arguments aren't allowed in TABLE functions")));
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index eae78fea8f..e9b456dd85 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -50,7 +50,9 @@ static Node *ParseComplexProjection(ParseState *pstate, const char *funcname,
Node *first_arg, int location);
static Oid LookupFuncNameInternal(List *funcname, int nargs,
const Oid *argtypes,
- bool missing_ok, FuncLookupError *lookupError);
+ ObjectType objtype,
+ bool include_out_arguments, bool missing_ok,
+ FuncLookupError *lookupError);
/*
@@ -2044,12 +2046,15 @@ func_signature_string(List *funcname, int nargs,
*
* Possible errors:
* FUNCLOOKUP_NOSUCHFUNC: we can't find a function of this name.
- * FUNCLOOKUP_AMBIGUOUS: nargs == -1 and more than one function matches.
+ * FUNCLOOKUP_AMBIGUOUS: more than one function matches.
*/
static Oid
LookupFuncNameInternal(List *funcname, int nargs, const Oid *argtypes,
- bool missing_ok, FuncLookupError *lookupError)
+ ObjectType objtype,
+ bool include_out_arguments, bool missing_ok,
+ FuncLookupError *lookupError)
{
+ Oid result = InvalidOid;
FuncCandidateList clist;
/* NULL argtypes allowed for nullary functions only */
@@ -2058,43 +2063,62 @@ LookupFuncNameInternal(List *funcname, int nargs, const Oid *argtypes,
/* Always set *lookupError, to forestall uninitialized-variable warnings */
*lookupError = FUNCLOOKUP_NOSUCHFUNC;
+ /* Get list of candidate objects */
clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false,
- false, missing_ok);
+ include_out_arguments, missing_ok);
- /*
- * If no arguments were specified, the name must yield a unique candidate.
- */
- if (nargs < 0)
+ /* Scan list for a match to the arg types (if specified) and the objtype */
+ for (; clist != NULL; clist = clist->next)
{
- if (clist)
+ /* Check arg type match, if specified */
+ if (nargs >= 0)
{
- /* If there is a second match then it's ambiguous */
- if (clist->next)
- {
- *lookupError = FUNCLOOKUP_AMBIGUOUS;
- return InvalidOid;
- }
- /* Otherwise return the match */
- return clist->oid;
+ /* if nargs==0, argtypes can be null; don't pass that to memcmp */
+ if (nargs > 0 &&
+ memcmp(argtypes, clist->args, nargs * sizeof(Oid)) != 0)
+ continue;
}
- else
+
+ /* Check for duplicates reported by FuncnameGetCandidates */
+ if (!OidIsValid(clist->oid))
+ {
+ *lookupError = FUNCLOOKUP_AMBIGUOUS;
return InvalidOid;
- }
+ }
- /*
- * Otherwise, look for a match to the arg types. FuncnameGetCandidates
- * has ensured that there's at most one match in the returned list.
- */
- while (clist)
- {
- /* if nargs==0, argtypes can be null; don't pass that to memcmp */
- if (nargs == 0 ||
- memcmp(argtypes, clist->args, nargs * sizeof(Oid)) == 0)
- return clist->oid;
- clist = clist->next;
+ /* Check objtype match, if specified */
+ switch (objtype)
+ {
+ case OBJECT_FUNCTION:
+ case OBJECT_AGGREGATE:
+ /* Ignore procedures */
+ if (get_func_prokind(clist->oid) == PROKIND_PROCEDURE)
+ continue;
+ break;
+ case OBJECT_PROCEDURE:
+ /* Ignore non-procedures */
+ if (get_func_prokind(clist->oid) != PROKIND_PROCEDURE)
+ continue;
+ break;
+ case OBJECT_ROUTINE:
+ /* no restriction */
+ break;
+ default:
+ Assert(false);
+ }
+
+ /* Check for multiple matches */
+ if (OidIsValid(result))
+ {
+ *lookupError = FUNCLOOKUP_AMBIGUOUS;
+ return InvalidOid;
+ }
+
+ /* OK, we have a candidate */
+ result = clist->oid;
}
- return InvalidOid;
+ return result;
}
/*
@@ -2121,7 +2145,9 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Oid funcoid;
FuncLookupError lookupError;
- funcoid = LookupFuncNameInternal(funcname, nargs, argtypes, missing_ok,
+ funcoid = LookupFuncNameInternal(funcname, nargs, argtypes,
+ OBJECT_ROUTINE, /* XXX okay? */
+ false, missing_ok,
&lookupError);
if (OidIsValid(funcoid))
@@ -2210,10 +2236,14 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
FUNC_MAX_ARGS)));
}
+ /*
+ * First, perform a lookup considering only input arguments (traditional
+ * Postgres rules).
+ */
i = 0;
foreach(args_item, func->objargs)
{
- TypeName *t = (TypeName *) lfirst(args_item);
+ TypeName *t = lfirst_node(TypeName, args_item);
argoids[i] = LookupTypeNameOid(NULL, t, missing_ok);
if (!OidIsValid(argoids[i]))
@@ -2227,9 +2257,82 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
*/
nargs = func->args_unspecified ? -1 : argcount;
- oid = LookupFuncNameInternal(func->objname, nargs, argoids, missing_ok,
+ /*
+ * In args_unspecified mode, also tell LookupFuncNameInternal to consider
+ * the object type, since there seems no reason not to. However, if we
+ * have an argument list, disable the objtype check, because we'd rather
+ * complain about "object is of wrong type" than "object doesn't exist".
+ * (Note that with args, FuncnameGetCandidates will have ensured there's
+ * only one argtype match, so we're not risking an ambiguity failure via
+ * this choice.)
+ */
+ oid = LookupFuncNameInternal(func->objname, nargs, argoids,
+ func->args_unspecified ? objtype : OBJECT_ROUTINE,
+ false, missing_ok,
&lookupError);
+ /*
+ * If PROCEDURE or ROUTINE was specified, and we have an argument list
+ * that contains no parameter mode markers, and we didn't already discover
+ * that there's ambiguity, perform a lookup considering all arguments.
+ * (Note: for a zero-argument procedure, or in args_unspecified mode, the
+ * normal lookup is sufficient; so it's OK to require non-NIL objfuncargs
+ * to perform this lookup.)
+ */
+ if ((objtype == OBJECT_PROCEDURE || objtype == OBJECT_ROUTINE) &&
+ func->objfuncargs != NIL &&
+ lookupError != FUNCLOOKUP_AMBIGUOUS)
+ {
+ bool have_param_mode = false;
+
+ /*
+ * Check for non-default parameter mode markers. If there are any,
+ * then the command does not conform to SQL-spec syntax, so we may
+ * assume that the traditional Postgres lookup method of considering
+ * only input parameters is sufficient. (Note that because the spec
+ * doesn't have OUT arguments for functions, we also don't need this
+ * hack in FUNCTION or AGGREGATE mode.)
+ */
+ foreach(args_item, func->objfuncargs)
+ {
+ FunctionParameter *fp = lfirst_node(FunctionParameter, args_item);
+
+ if (fp->mode != FUNC_PARAM_DEFAULT)
+ {
+ have_param_mode = true;
+ break;
+ }
+ }
+
+ if (!have_param_mode)
+ {
+ Oid poid;
+
+ /* Without mode marks, objargs surely includes all params */
+ Assert(list_length(func->objfuncargs) == argcount);
+
+ /* For objtype == OBJECT_PROCEDURE, we can ignore non-procedures */
+ poid = LookupFuncNameInternal(func->objname, argcount, argoids,
+ objtype, true, missing_ok,
+ &lookupError);
+
+ /* Combine results, handling ambiguity */
+ if (OidIsValid(poid))
+ {
+ if (OidIsValid(oid) && oid != poid)
+ {
+ /* oops, we got hits both ways, on different objects */
+ oid = InvalidOid;
+ lookupError = FUNCLOOKUP_AMBIGUOUS;
+ }
+ else
+ oid = poid;
+ }
+ else if (lookupError == FUNCLOOKUP_AMBIGUOUS)
+ oid = InvalidOid;
+ }
+ }
+
if (OidIsValid(oid))
{
/*
@@ -2238,6 +2341,10 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
* we allow the objtype of FUNCTION to include aggregates and window
* functions; but we draw the line if the object is a procedure. That
* is a new enough feature that this historical rule does not apply.
+ *
+ * (This check is partially redundant with the objtype check in
+ * LookupFuncNameInternal; but not entirely, since we often don't tell
+ * LookupFuncNameInternal to apply that check at all.)
*/
switch (objtype)
{
@@ -2348,28 +2455,32 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("function name \"%s\" is not unique",
NameListToString(func->objname)),
- errhint("Specify the argument list to select the function unambiguously.")));
+ func->args_unspecified ?
+ errhint("Specify the argument list to select the function unambiguously.") : 0));
break;
case OBJECT_PROCEDURE:
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("procedure name \"%s\" is not unique",
NameListToString(func->objname)),
- errhint("Specify the argument list to select the procedure unambiguously.")));
+ func->args_unspecified ?
+ errhint("Specify the argument list to select the procedure unambiguously.") : 0));
break;
case OBJECT_AGGREGATE:
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("aggregate name \"%s\" is not unique",
NameListToString(func->objname)),
- errhint("Specify the argument list to select the aggregate unambiguously.")));
+ func->args_unspecified ?
+ errhint("Specify the argument list to select the aggregate unambiguously.") : 0));
break;
case OBJECT_ROUTINE:
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("routine name \"%s\" is not unique",
NameListToString(func->objname)),
- errhint("Specify the argument list to select the routine unambiguously.")));
+ func->args_unspecified ?
+ errhint("Specify the argument list to select the routine unambiguously.") : 0));
break;
default:
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index c379d72fce..4e46079990 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -150,8 +150,8 @@ LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
rightoid;
Assert(list_length(oper->objargs) == 2);
- oprleft = linitial(oper->objargs);
- oprright = lsecond(oper->objargs);
+ oprleft = linitial_node(TypeName, oper->objargs);
+ oprright = lsecond_node(TypeName, oper->objargs);
if (oprleft == NULL)
leftoid = InvalidOid;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index fb3d7ab8ef..3719755a0d 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3217,7 +3217,15 @@ print_function_arguments(StringInfo buf, HeapTuple proctup,
switch (argmode)
{
case PROARGMODE_IN:
- modename = "";
+
+ /*
+ * For procedures, explicitly mark all argument modes, so as
+ * to avoid ambiguity with the SQL syntax for DROP PROCEDURE.
+ */
+ if (proc->prokind == PROKIND_PROCEDURE)
+ modename = "IN ";
+ else
+ modename = "";
isinput = true;
break;
case PROARGMODE_INOUT:
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 4bc845e57c..244507c97c 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -1898,7 +1898,7 @@ my %tests = (
create_sql => 'CREATE PROCEDURE dump_test.ptest1(a int)
LANGUAGE SQL AS $$ INSERT INTO dump_test.test_table (col1) VALUES (a) $$;',
regexp => qr/^
- \QCREATE PROCEDURE dump_test.ptest1(a integer)\E
+ \QCREATE PROCEDURE dump_test.ptest1(IN a integer)\E
\n\s+\QLANGUAGE sql\E
\n\s+AS\ \$\$\Q INSERT INTO dump_test.test_table (col1) VALUES (a) \E\$\$;
/xm,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 04789614ce..58328c4377 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2024,18 +2024,29 @@ typedef struct GrantStmt
} GrantStmt;
/*
- * Note: ObjectWithArgs carries only the types of the input parameters of the
- * function. So it is sufficient to identify an existing function, but it
- * is not enough info to define a function nor to call it.
+ * ObjectWithArgs represents a function/procedure/operator name plus parameter
+ * identification.
+ *
+ * objargs includes only the types of the input parameters of the object.
+ * In some contexts, that will be all we have, and it's enough to look up
+ * objects according to the traditional Postgres rules (i.e., when only input
+ * arguments matter).
+ *
+ * objfuncargs, if not NIL, carries the full specification of the parameter
+ * list, including parameter mode annotations.
+ *
+ * Some grammar productions can set args_unspecified = true instead of
+ * providing parameter info. In this case, lookup will succeed only if
+ * the object name is unique. Note that otherwise, NIL parameter lists
+ * mean zero arguments.
*/
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) */
+ List *objargs; /* list of Typename nodes (input args only) */
+ List *objfuncargs; /* list of FunctionParameter nodes */
+ bool args_unspecified; /* argument list was omitted? */
} ObjectWithArgs;
/*
@@ -2955,7 +2966,9 @@ typedef enum FunctionParameterMode
FUNC_PARAM_OUT = 'o', /* output only */
FUNC_PARAM_INOUT = 'b', /* both */
FUNC_PARAM_VARIADIC = 'v', /* variadic (always input) */
- FUNC_PARAM_TABLE = 't' /* table function output column */
+ FUNC_PARAM_TABLE = 't', /* table function output column */
+ /* this is not used in pg_proc: */
+ FUNC_PARAM_DEFAULT = 'd' /* default; effectively same as IN */
} FunctionParameterMode;
typedef struct FunctionParameter
diff --git a/src/test/regress/expected/create_procedure.out b/src/test/regress/expected/create_procedure.out
index ec884c4d70..46c827f979 100644
--- a/src/test/regress/expected/create_procedure.out
+++ b/src/test/regress/expected/create_procedure.out
@@ -19,17 +19,17 @@ $$;
List of functions
Schema | Name | Result data type | Argument data types | Type
--------+--------+------------------+---------------------+------
- public | ptest1 | | x text | proc
+ public | ptest1 | | IN x text | proc
(1 row)
SELECT pg_get_functiondef('ptest1'::regproc);
- pg_get_functiondef
----------------------------------------------------
- CREATE OR REPLACE PROCEDURE public.ptest1(x text)+
- LANGUAGE sql +
- AS $procedure$ +
- INSERT INTO cp_test VALUES (1, x); +
- $procedure$ +
+ pg_get_functiondef
+------------------------------------------------------
+ CREATE OR REPLACE PROCEDURE public.ptest1(IN x text)+
+ LANGUAGE sql +
+ AS $procedure$ +
+ INSERT INTO cp_test VALUES (1, x); +
+ $procedure$ +
(1 row)
@@ -46,7 +46,7 @@ SELECT pg_get_functiondef('ptest1'::regproc);
List of functions
Schema | Name | Result data type | Argument data types | Type
--------+--------+------------------+---------------------+------
- public | ptest1 | | x text | proc
+ public | ptest1 | | IN x text | proc
(1 row)
SELECT ptest1('x'); -- error
@@ -75,18 +75,18 @@ END;
List of functions
Schema | Name | Result data type | Argument data types | Type
--------+---------+------------------+---------------------+------
- public | ptest1s | | x text | proc
+ public | ptest1s | | IN x text | proc
(1 row)
SELECT pg_get_functiondef('ptest1s'::regproc);
- pg_get_functiondef
-----------------------------------------------------
- CREATE OR REPLACE PROCEDURE public.ptest1s(x text)+
- LANGUAGE sql +
- BEGIN ATOMIC +
- INSERT INTO cp_test (a, b) +
- VALUES (1, ptest1s.x); +
- END +
+ pg_get_functiondef
+-------------------------------------------------------
+ CREATE OR REPLACE PROCEDURE public.ptest1s(IN x text)+
+ LANGUAGE sql +
+ BEGIN ATOMIC +
+ INSERT INTO cp_test (a, b) +
+ VALUES (1, ptest1s.x); +
+ END +
(1 row)
@@ -196,16 +196,16 @@ END;
List of functions
Schema | Name | Result data type | Argument data types | Type
--------+--------+------------------+---------------------+------
- public | ptest8 | | x text | proc
+ public | ptest8 | | IN x text | proc
(1 row)
SELECT pg_get_functiondef('ptest8'::regproc);
- pg_get_functiondef
----------------------------------------------------
- CREATE OR REPLACE PROCEDURE public.ptest8(x text)+
- LANGUAGE sql +
- BEGIN ATOMIC +
- END +
+ pg_get_functiondef
+------------------------------------------------------
+ CREATE OR REPLACE PROCEDURE public.ptest8(IN x text)+
+ LANGUAGE sql +
+ BEGIN ATOMIC +
+ END +
(1 row)
@@ -278,6 +278,44 @@ CALL ptest11(null, 11, 12, 13);
23
(1 row)
+-- check resolution of ambiguous DROP commands
+CREATE PROCEDURE ptest10(IN a int, IN b int, IN c int)
+LANGUAGE SQL AS $$ SELECT a + b - c $$;
+\df ptest10
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+---------+------------------+-------------------------------------------+------
+ public | ptest10 | | IN a integer, IN b integer, IN c integer | proc
+ public | ptest10 | | OUT a integer, IN b integer, IN c integer | proc
+(2 rows)
+
+drop procedure ptest10; -- fail
+ERROR: procedure name "ptest10" is not unique
+HINT: Specify the argument list to select the procedure unambiguously.
+drop procedure ptest10(int, int, int); -- fail
+ERROR: procedure name "ptest10" is not unique
+begin;
+drop procedure ptest10(out int, int, int);
+\df ptest10
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+---------+------------------+------------------------------------------+------
+ public | ptest10 | | IN a integer, IN b integer, IN c integer | proc
+(1 row)
+
+drop procedure ptest10(int, int, int); -- now this would work
+rollback;
+begin;
+drop procedure ptest10(in int, int, int);
+\df ptest10
+ List of functions
+ Schema | Name | Result data type | Argument data types | Type
+--------+---------+------------------+-------------------------------------------+------
+ public | ptest10 | | OUT a integer, IN b integer, IN c integer | proc
+(1 row)
+
+drop procedure ptest10(int, int, int); -- now this would work
+rollback;
-- various error cases
CALL version(); -- error: not a procedure
ERROR: version() is not a procedure
diff --git a/src/test/regress/sql/create_procedure.sql b/src/test/regress/sql/create_procedure.sql
index b835ab7ec0..75cc0fcf2a 100644
--- a/src/test/regress/sql/create_procedure.sql
+++ b/src/test/regress/sql/create_procedure.sql
@@ -175,6 +175,25 @@ CREATE PROCEDURE ptest11(a OUT int, VARIADIC b int[]) LANGUAGE SQL
CALL ptest11(null, 11, 12, 13);
+-- check resolution of ambiguous DROP commands
+
+CREATE PROCEDURE ptest10(IN a int, IN b int, IN c int)
+LANGUAGE SQL AS $$ SELECT a + b - c $$;
+
+\df ptest10
+
+drop procedure ptest10; -- fail
+drop procedure ptest10(int, int, int); -- fail
+begin;
+drop procedure ptest10(out int, int, int);
+\df ptest10
+drop procedure ptest10(int, int, int); -- now this would work
+rollback;
+begin;
+drop procedure ptest10(in int, int, int);
+\df ptest10
+drop procedure ptest10(int, int, int); -- now this would work
+rollback;
-- various error cases