Commit 676bb1ab authored by Tom Lane's avatar Tom Lane

Add a hack requested by the JDBC driver writers: when a function's

argument list contains parameter symbols ($n) declared as type VOID,
discard these arguments.  This allows the driver to avoid renumbering
mixed IN and OUT argument placeholders (the JDBC syntax involves writing
? for both IN and OUT parameters, but on the server side we don't think
that OUT parameters are arguments).  This doesn't break any currently-
useful cases since VOID is not used as an input argument type.
parent 738df437
<!-- $PostgreSQL: pgsql/doc/src/sgml/protocol.sgml,v 1.58 2005/01/23 00:30:18 momjian Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/protocol.sgml,v 1.59 2005/06/22 15:19:43 tgl Exp $ -->
<chapter id="protocol"> <chapter id="protocol">
<title>Frontend/Backend Protocol</title> <title>Frontend/Backend Protocol</title>
...@@ -639,6 +639,24 @@ ...@@ -639,6 +639,24 @@
constants. constants.
</para> </para>
<note>
<para>
A parameter data type can be left unspecified by setting it to zero,
or by making the array of parameter type OIDs shorter than the
number of parameter symbols (<literal>$</><replaceable>n</>)
used in the query string. Another special case is that a parameter's
type can be specified as <type>void</> (that is, the OID of the
<type>void</> pseudotype). This is meant to allow parameter symbols
to be used for function parameters that are actually OUT parameters.
Ordinarily there is no context in which a <type>void</> parameter
could be used, but if such a parameter symbol appears in a function's
parameter list, it is effectively ignored. For example, a function
call such as <literal>foo($1,$2,$3,$4)</> could match a function with
two IN and two OUT arguments, if <literal>$3</> and <literal>$4</>
are specified as having type <type>void</>.
</para>
</note>
<note> <note>
<para> <para>
The query string contained in a Parse message cannot include more The query string contained in a Parse message cannot include more
...@@ -670,6 +688,8 @@ ...@@ -670,6 +688,8 @@
the values to use for any parameter placeholders present in the prepared the values to use for any parameter placeholders present in the prepared
statement. The statement. The
supplied parameter set must match those needed by the prepared statement. supplied parameter set must match those needed by the prepared statement.
(If you declared any <type>void</> parameters in the Parse message,
pass NULL values for them in the Bind message.)
Bind also specifies the format to use for any data returned Bind also specifies the format to use for any data returned
by the query; the format can be specified overall, or per-column. by the query; the format can be specified overall, or per-column.
The response is either BindComplete or ErrorResponse. The response is either BindComplete or ErrorResponse.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.180 2005/05/31 01:03:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.181 2005/06/22 15:19:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -64,9 +64,9 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, ...@@ -64,9 +64,9 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
Oid rettype; Oid rettype;
Oid funcid; Oid funcid;
ListCell *l; ListCell *l;
ListCell *nextl;
Node *first_arg = NULL; Node *first_arg = NULL;
int nargs = list_length(fargs); int nargs;
int argn;
Oid actual_arg_types[FUNC_MAX_ARGS]; Oid actual_arg_types[FUNC_MAX_ARGS];
Oid *declared_arg_types; Oid *declared_arg_types;
Node *retval; Node *retval;
...@@ -79,12 +79,38 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, ...@@ -79,12 +79,38 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
* protect against array overruns, etc. Of course, this may not be a * protect against array overruns, etc. Of course, this may not be a
* function, but the test doesn't hurt. * function, but the test doesn't hurt.
*/ */
if (nargs > FUNC_MAX_ARGS) if (list_length(fargs) > FUNC_MAX_ARGS)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS), (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
errmsg("cannot pass more than %d arguments to a function", errmsg("cannot pass more than %d arguments to a function",
FUNC_MAX_ARGS))); FUNC_MAX_ARGS)));
/*
* Extract arg type info in preparation for function lookup.
*
* If any arguments are Param markers of type VOID, we discard them
* from the parameter list. This is a hack to allow the JDBC driver
* to not have to distinguish "input" and "output" parameter symbols
* while parsing function-call constructs. We can't use foreach()
* because we may modify the list ...
*/
nargs = 0;
for (l = list_head(fargs); l != NULL; l = nextl)
{
Node *arg = lfirst(l);
Oid argtype = exprType(arg);
nextl = lnext(l);
if (argtype == VOIDOID && IsA(arg, Param) && !is_column)
{
fargs = list_delete_ptr(fargs, arg);
continue;
}
actual_arg_types[nargs++] = argtype;
}
if (fargs) if (fargs)
{ {
first_arg = linitial(fargs); first_arg = linitial(fargs);
...@@ -99,7 +125,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, ...@@ -99,7 +125,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
*/ */
if (nargs == 1 && !agg_star && !agg_distinct && list_length(funcname) == 1) if (nargs == 1 && !agg_star && !agg_distinct && list_length(funcname) == 1)
{ {
Oid argtype = exprType(first_arg); Oid argtype = actual_arg_types[0];
if (argtype == RECORDOID || ISCOMPLEX(argtype)) if (argtype == RECORDOID || ISCOMPLEX(argtype))
{ {
...@@ -117,18 +143,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, ...@@ -117,18 +143,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
} }
/* /*
* Okay, it's not a column projection, so it must really be a * Okay, it's not a column projection, so it must really be a function.
* function. Extract arg type info in preparation for function lookup.
*/
argn = 0;
foreach(l, fargs)
{
Node *arg = lfirst(l);
actual_arg_types[argn++] = exprType(arg);
}
/*
* func_get_detail looks up the function in the catalogs, does * func_get_detail looks up the function in the catalogs, does
* disambiguation for polymorphic functions, handles inheritance, and * disambiguation for polymorphic functions, handles inheritance, and
* returns the funcid and type and set or singleton status of the * returns the funcid and type and set or singleton status of the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment