Commit 16503e6f authored by Tom Lane's avatar Tom Lane

Extended query protocol: parse, bind, execute, describe FE/BE messages.

Only lightly tested as yet, since libpq doesn't know anything about 'em.
parent a59793f8
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.33 2003/04/28 05:17:31 tgl Exp $ --> <!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.34 2003/05/05 00:44:55 tgl Exp $ -->
<chapter id="protocol"> <chapter id="protocol">
<title>Frontend/Backend Protocol</title> <title>Frontend/Backend Protocol</title>
...@@ -595,7 +595,11 @@ ...@@ -595,7 +595,11 @@
<para> <para>
If successfully created, a named prepared-statement object lasts till If successfully created, a named prepared-statement object lasts till
the end of the current session, unless explicitly destroyed. An unnamed the end of the current session, unless explicitly destroyed. An unnamed
prepared statement lasts only until the next Parse message is issued. prepared statement lasts only until the next Parse statement specifying
the unnamed statement as destination is issued. (Note that a simple
Query message also destroys the unnamed statement.) Named prepared
statements must be explicitly closed before they can be redefined by
a Parse message, but this is not required for the unnamed statement.
Named prepared statements can also be created and accessed at the SQL Named prepared statements can also be created and accessed at the SQL
command level, using <command>PREPARE</> and <command>EXECUTE</>. command level, using <command>PREPARE</> and <command>EXECUTE</>.
</para> </para>
...@@ -611,10 +615,13 @@ ...@@ -611,10 +615,13 @@
</para> </para>
<para> <para>
If successfully created, a named portal object lasts till If successfully created, a named portal object lasts till the end of the
the end of the current transaction, unless explicitly destroyed. An current transaction, unless explicitly destroyed. An unnamed portal is
unnamed portal is destroyed at the end of the transaction, or as soon destroyed at the end of the transaction, or as soon as the next Bind
as the next Parse or Bind message is executed. statement specifying the unnamed portal as destination is issued. (Note
that a simple Query message also destroys the unnamed portal.) Named
portals must be explicitly closed before they can be redefined by a Bind
message, but this is not required for the unnamed portal.
Named portals can also be created and accessed at the SQL Named portals can also be created and accessed at the SQL
command level, using <command>DECLARE CURSOR</> and <command>FETCH</>. command level, using <command>DECLARE CURSOR</> and <command>FETCH</>.
</para> </para>
...@@ -691,17 +698,19 @@ ...@@ -691,17 +698,19 @@
The Describe message (statement variant) specifies the name of an existing The Describe message (statement variant) specifies the name of an existing
prepared statement (or an empty string for the unnamed prepared prepared statement (or an empty string for the unnamed prepared
statement). The response is a ParameterDescription message describing the statement). The response is a ParameterDescription message describing the
parameters needed by the statement (if any), followed by a RowDescription parameters needed by the statement. ErrorResponse is issued if there is
message describing the rows that will be returned when the statement is no such prepared statement. This message may be useful if the client
eventually executed (or NoData if there is no SELECT-type query in the library is uncertain about the parameters needed by a prepared statement.
prepared statement). ErrorResponse is issued if there is no such prepared
statement. This message may be useful if the client library is
uncertain about the parameters needed by a prepared statement.
</para> </para>
<para> <para>
The Close message closes an existing prepared statement or portal The Close message closes an existing prepared statement or portal
and releases resources. and releases resources. It is not an error to issue Close against
a nonexistent statement or portal name. The response is normally
CloseComplete, but could be ErrorResponse if some difficulty is
encountered while releasing resources. Note that closing a prepared
statement implicitly closes any open portals that were constructed
from that statement.
</para> </para>
<para> <para>
...@@ -709,19 +718,20 @@ ...@@ -709,19 +718,20 @@
but forces the backend to deliver any data pending in its output but forces the backend to deliver any data pending in its output
buffers. A Flush must be sent after any extended-query command except buffers. A Flush must be sent after any extended-query command except
Sync, if the frontend wishes to examine the results of that command before Sync, if the frontend wishes to examine the results of that command before
issuing more commands. Without Flush, returning data will be combined issuing more commands. Without Flush, messages returned by the backend
into the minimum possible number of packets to minimize network overhead. will be combined into the minimum possible number of packets to minimize
network overhead.
</para> </para>
<note> <note>
<para> <para>
The simple Query message is approximately equivalent to the series Parse, The simple Query message is approximately equivalent to the series Parse,
Bind, portal Describe, Execute, Sync, using the unnamed prepared statement Bind, portal Describe, Execute, Close, Sync, using the unnamed prepared
and portal objects and no parameters. One difference is that it statement and portal objects and no parameters. One difference is that
will accept multiple SQL statements in the query string, automatically it will accept multiple SQL statements in the query string, automatically
performing the bind/describe/execute sequence for each one in succession. performing the bind/describe/execute sequence for each one in succession.
Another is that it will not return ParseComplete, BindComplete, or Another difference is that it will not return ParseComplete, BindComplete,
NoData messages. CloseComplete, or NoData messages.
</para> </para>
</note> </note>
</sect2> </sect2>
...@@ -1917,6 +1927,41 @@ Close (F) ...@@ -1917,6 +1927,41 @@ Close (F)
</VarListEntry> </VarListEntry>
<VarListEntry>
<Term>
CloseComplete (B)
</Term>
<ListItem>
<Para>
<VariableList>
<VarListEntry>
<Term>
Byte1('3')
</Term>
<ListItem>
<Para>
Identifies the message as a Close-complete indicator.
</Para>
</ListItem>
</VarListEntry>
<VarListEntry>
<Term>
Int32(4)
</Term>
<ListItem>
<Para>
Length of message contents in bytes, including self.
</Para>
</ListItem>
</VarListEntry>
</VariableList>
</Para>
</ListItem>
</VarListEntry>
<VarListEntry> <VarListEntry>
<Term> <Term>
CommandComplete (B) CommandComplete (B)
...@@ -3875,6 +3920,15 @@ The ReadyForQuery ('<literal>Z</>') message includes a transaction status ...@@ -3875,6 +3920,15 @@ The ReadyForQuery ('<literal>Z</>') message includes a transaction status
indicator. indicator.
</para> </para>
<para>
There is a new <quote>extended query</> sub-protocol, which adds the frontend
message types Parse, Bind, Execute, Describe, Close, Flush, and Sync, and the
backend message types ParseComplete, BindComplete, PortalSuspended,
ParameterDescription, NoData, and CloseComplete. Existing clients do not
have to concern themselves with this sub-protocol, but making use of it
may allow improvements in performance or functionality.
</para>
<para> <para>
COPY data is now encapsulated into CopyData and CopyDone messages. There COPY data is now encapsulated into CopyData and CopyDone messages. There
is a well-defined way to recover from errors during COPY. The special is a well-defined way to recover from errors during COPY. The special
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.67 2003/04/26 20:22:58 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.68 2003/05/05 00:44:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -48,6 +48,7 @@ typedef struct ...@@ -48,6 +48,7 @@ typedef struct
typedef struct typedef struct
{ {
DestReceiver pub; /* publicly-known function pointers */ DestReceiver pub; /* publicly-known function pointers */
bool sendDescrip; /* send RowDescription at startup? */
TupleDesc attrinfo; /* The attr info we are set up for */ TupleDesc attrinfo; /* The attr info we are set up for */
int nattrs; int nattrs;
PrinttupAttrInfo *myinfo; /* Cached info about each attr */ PrinttupAttrInfo *myinfo; /* Cached info about each attr */
...@@ -58,7 +59,7 @@ typedef struct ...@@ -58,7 +59,7 @@ typedef struct
* ---------------- * ----------------
*/ */
DestReceiver * DestReceiver *
printtup_create_DR(bool isBinary) printtup_create_DR(bool isBinary, bool sendDescrip)
{ {
DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup)); DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup));
...@@ -66,6 +67,8 @@ printtup_create_DR(bool isBinary) ...@@ -66,6 +67,8 @@ printtup_create_DR(bool isBinary)
self->pub.setup = printtup_setup; self->pub.setup = printtup_setup;
self->pub.cleanup = printtup_cleanup; self->pub.cleanup = printtup_cleanup;
self->sendDescrip = sendDescrip;
self->attrinfo = NULL; self->attrinfo = NULL;
self->nattrs = 0; self->nattrs = 0;
self->myinfo = NULL; self->myinfo = NULL;
...@@ -77,6 +80,8 @@ static void ...@@ -77,6 +80,8 @@ static void
printtup_setup(DestReceiver *self, int operation, printtup_setup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo) const char *portalName, TupleDesc typeinfo)
{ {
DR_printtup *myState = (DR_printtup *) self;
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
{ {
/* /*
...@@ -91,11 +96,30 @@ printtup_setup(DestReceiver *self, int operation, ...@@ -91,11 +96,30 @@ printtup_setup(DestReceiver *self, int operation,
} }
/* /*
* if this is a retrieve, then we send back the tuple descriptor of * If this is a retrieve, and we are supposed to emit row descriptions,
* the tuples. * then we send back the tuple descriptor of the tuples.
*/ */
if (operation == CMD_SELECT) if (operation == CMD_SELECT && myState->sendDescrip)
{ SendRowDescriptionMessage(typeinfo);
/* ----------------
* We could set up the derived attr info at this time, but we postpone it
* until the first call of printtup, for 2 reasons:
* 1. We don't waste time (compared to the old way) if there are no
* tuples at all to output.
* 2. Checking in printtup allows us to handle the case that the tuples
* change type midway through (although this probably can't happen in
* the current executor).
* ----------------
*/
}
/*
* SendRowDescriptionMessage --- send a RowDescription message to the frontend
*/
void
SendRowDescriptionMessage(TupleDesc typeinfo)
{
Form_pg_attribute *attrs = typeinfo->attrs; Form_pg_attribute *attrs = typeinfo->attrs;
int natts = typeinfo->natts; int natts = typeinfo->natts;
int proto = PG_PROTOCOL_MAJOR(FrontendProtocol); int proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
...@@ -125,18 +149,6 @@ printtup_setup(DestReceiver *self, int operation, ...@@ -125,18 +149,6 @@ printtup_setup(DestReceiver *self, int operation,
sizeof(attrs[i]->atttypmod)); sizeof(attrs[i]->atttypmod));
} }
pq_endmessage(&buf); pq_endmessage(&buf);
}
/* ----------------
* We could set up the derived attr info at this time, but we postpone it
* until the first call of printtup, for 2 reasons:
* 1. We don't waste time (compared to the old way) if there are no
* tuples at all to output.
* 2. Checking in printtup allows us to handle the case that the tuples
* change type midway through (although this probably can't happen in
* the current executor).
* ----------------
*/
} }
static void static void
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.13 2003/05/02 20:54:33 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.14 2003/05/05 00:44:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -49,7 +49,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest) ...@@ -49,7 +49,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest)
* Disallow empty-string cursor name (conflicts with protocol-level * Disallow empty-string cursor name (conflicts with protocol-level
* unnamed portal). * unnamed portal).
*/ */
if (strlen(stmt->portalname) == 0) if (!stmt->portalname || stmt->portalname[0] == '\0')
elog(ERROR, "Invalid cursor name: must not be empty"); elog(ERROR, "Invalid cursor name: must not be empty");
/* /*
...@@ -148,6 +148,13 @@ PerformPortalFetch(FetchStmt *stmt, ...@@ -148,6 +148,13 @@ PerformPortalFetch(FetchStmt *stmt,
Portal portal; Portal portal;
long nprocessed; long nprocessed;
/*
* Disallow empty-string cursor name (conflicts with protocol-level
* unnamed portal).
*/
if (!stmt->portalname || stmt->portalname[0] == '\0')
elog(ERROR, "Invalid cursor name: must not be empty");
/* get the portal from the portal name */ /* get the portal from the portal name */
portal = GetPortalByName(stmt->portalname); portal = GetPortalByName(stmt->portalname);
if (!PortalIsValid(portal)) if (!PortalIsValid(portal))
...@@ -164,7 +171,9 @@ PerformPortalFetch(FetchStmt *stmt, ...@@ -164,7 +171,9 @@ PerformPortalFetch(FetchStmt *stmt,
* Adjust dest if needed. MOVE wants dest = None. * Adjust dest if needed. MOVE wants dest = None.
* *
* If fetching from a binary cursor and the requested destination is * If fetching from a binary cursor and the requested destination is
* Remote, change it to RemoteInternal. * Remote, change it to RemoteInternal. Note we do NOT change if the
* destination is RemoteExecute --- so the Execute message's format
* specification wins out over the cursor's type.
*/ */
if (stmt->ismove) if (stmt->ismove)
dest = None; dest = None;
...@@ -189,10 +198,17 @@ PerformPortalFetch(FetchStmt *stmt, ...@@ -189,10 +198,17 @@ PerformPortalFetch(FetchStmt *stmt,
* Close a cursor. * Close a cursor.
*/ */
void void
PerformPortalClose(char *name) PerformPortalClose(const char *name)
{ {
Portal portal; Portal portal;
/*
* Disallow empty-string cursor name (conflicts with protocol-level
* unnamed portal).
*/
if (!name || name[0] == '\0')
elog(ERROR, "Invalid cursor name: must not be empty");
/* /*
* get the portal from the portal name * get the portal from the portal name
*/ */
......
This diff is collapsed.
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.269 2003/05/02 20:54:34 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.270 2003/05/05 00:44:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -83,6 +83,12 @@ typedef struct ...@@ -83,6 +83,12 @@ typedef struct
IndexStmt *pkey; /* PRIMARY KEY index, if any */ IndexStmt *pkey; /* PRIMARY KEY index, if any */
} CreateStmtContext; } CreateStmtContext;
typedef struct
{
Oid *paramTypes;
int numParams;
} check_parameter_resolution_context;
static List *do_parse_analyze(Node *parseTree, ParseState *pstate); static List *do_parse_analyze(Node *parseTree, ParseState *pstate);
static Query *transformStmt(ParseState *pstate, Node *stmt, static Query *transformStmt(ParseState *pstate, Node *stmt,
...@@ -124,6 +130,8 @@ static void transformColumnType(ParseState *pstate, ColumnDef *column); ...@@ -124,6 +130,8 @@ static void transformColumnType(ParseState *pstate, ColumnDef *column);
static bool relationHasPrimaryKey(Oid relationOid); static bool relationHasPrimaryKey(Oid relationOid);
static void release_pstate_resources(ParseState *pstate); static void release_pstate_resources(ParseState *pstate);
static FromExpr *makeFromExpr(List *fromlist, Node *quals); static FromExpr *makeFromExpr(List *fromlist, Node *quals);
static bool check_parameter_resolution_walker(Node *node,
check_parameter_resolution_context *context);
/* /*
...@@ -179,6 +187,16 @@ parse_analyze_varparams(Node *parseTree, Oid **paramTypes, int *numParams) ...@@ -179,6 +187,16 @@ parse_analyze_varparams(Node *parseTree, Oid **paramTypes, int *numParams)
pfree(pstate); pfree(pstate);
/* make sure all is well with parameter types */
if (*numParams > 0)
{
check_parameter_resolution_context context;
context.paramTypes = *paramTypes;
context.numParams = *numParams;
check_parameter_resolution_walker((Node *) result, &context);
}
return result; return result;
} }
...@@ -2465,7 +2483,7 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt) ...@@ -2465,7 +2483,7 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
result->commandType = CMD_UTILITY; result->commandType = CMD_UTILITY;
result->utilityStmt = (Node *) stmt; result->utilityStmt = (Node *) stmt;
paramtypes = FetchQueryParams(stmt->name); paramtypes = FetchPreparedStatementParams(stmt->name);
if (stmt->params || paramtypes) if (stmt->params || paramtypes)
{ {
...@@ -2879,3 +2897,44 @@ analyzeCreateSchemaStmt(CreateSchemaStmt *stmt) ...@@ -2879,3 +2897,44 @@ analyzeCreateSchemaStmt(CreateSchemaStmt *stmt)
return result; return result;
} }
/*
* Traverse a fully-analyzed tree to verify that parameter symbols
* match their types. We need this because some Params might still
* be UNKNOWN, if there wasn't anything to force their coercion,
* and yet other instances seen later might have gotten coerced.
*/
static bool
check_parameter_resolution_walker(Node *node,
check_parameter_resolution_context *context)
{
if (node == NULL)
return false;
if (IsA(node, Param))
{
Param *param = (Param *) node;
if (param->paramkind == PARAM_NUM)
{
int paramno = param->paramid;
if (paramno <= 0 || /* shouldn't happen, but... */
paramno > context->numParams)
elog(ERROR, "Parameter '$%d' is out of range", paramno);
if (param->paramtype != context->paramTypes[paramno-1])
elog(ERROR, "Could not determine datatype of parameter $%d",
paramno);
}
return false;
}
if (IsA(node, Query))
{
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
return query_tree_walker((Query *) node,
check_parameter_resolution_walker,
(void *) context, 0);
}
return expression_tree_walker(node, check_parameter_resolution_walker,
(void *) context);
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.54 2003/04/26 20:22:59 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.55 2003/05/05 00:44:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -91,10 +91,20 @@ DestToFunction(CommandDest dest) ...@@ -91,10 +91,20 @@ DestToFunction(CommandDest dest)
switch (dest) switch (dest)
{ {
case Remote: case Remote:
return printtup_create_DR(false); return printtup_create_DR(false, true);
case RemoteInternal: case RemoteInternal:
return printtup_create_DR(true); return printtup_create_DR(true, true);
case RemoteExecute:
/* like Remote, but suppress output of T message */
return printtup_create_DR(false, false);
case RemoteExecuteInternal:
return printtup_create_DR(true, false);
case None:
return &donothingDR;
case Debug: case Debug:
return &debugtupDR; return &debugtupDR;
...@@ -104,9 +114,6 @@ DestToFunction(CommandDest dest) ...@@ -104,9 +114,6 @@ DestToFunction(CommandDest dest)
case Tuplestore: case Tuplestore:
return tstoreReceiverCreateDR(); return tstoreReceiverCreateDR();
case None:
return &donothingDR;
} }
/* should never get here */ /* should never get here */
...@@ -124,13 +131,15 @@ EndCommand(const char *commandTag, CommandDest dest) ...@@ -124,13 +131,15 @@ EndCommand(const char *commandTag, CommandDest dest)
{ {
case Remote: case Remote:
case RemoteInternal: case RemoteInternal:
case RemoteExecute:
case RemoteExecuteInternal:
pq_puttextmessage('C', commandTag); pq_puttextmessage('C', commandTag);
break; break;
case None: case None:
case Debug: case Debug:
case Tuplestore:
case SPI: case SPI:
case Tuplestore:
break; break;
} }
} }
...@@ -152,8 +161,10 @@ NullCommand(CommandDest dest) ...@@ -152,8 +161,10 @@ NullCommand(CommandDest dest)
{ {
switch (dest) switch (dest)
{ {
case RemoteInternal:
case Remote: case Remote:
case RemoteInternal:
case RemoteExecute:
case RemoteExecuteInternal:
/* /*
* tell the fe that we saw an empty query string. In protocols * tell the fe that we saw an empty query string. In protocols
...@@ -165,10 +176,10 @@ NullCommand(CommandDest dest) ...@@ -165,10 +176,10 @@ NullCommand(CommandDest dest)
pq_puttextmessage('I', ""); pq_puttextmessage('I', "");
break; break;
case None:
case Debug: case Debug:
case SPI:
case Tuplestore: case Tuplestore:
case None:
default:
break; break;
} }
} }
...@@ -189,8 +200,10 @@ ReadyForQuery(CommandDest dest) ...@@ -189,8 +200,10 @@ ReadyForQuery(CommandDest dest)
{ {
switch (dest) switch (dest)
{ {
case RemoteInternal:
case Remote: case Remote:
case RemoteInternal:
case RemoteExecute:
case RemoteExecuteInternal:
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{ {
StringInfoData buf; StringInfoData buf;
...@@ -205,10 +218,10 @@ ReadyForQuery(CommandDest dest) ...@@ -205,10 +218,10 @@ ReadyForQuery(CommandDest dest)
pq_flush(); pq_flush();
break; break;
case None:
case Debug: case Debug:
case SPI:
case Tuplestore: case Tuplestore:
case None:
default:
break; break;
} }
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.60 2003/05/02 20:54:35 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.61 2003/05/05 00:44:56 tgl Exp $
* *
* NOTES * NOTES
* This cruft is the server side of PQfn. * This cruft is the server side of PQfn.
...@@ -310,6 +310,14 @@ HandleFunctionRequest(StringInfo msgBuf) ...@@ -310,6 +310,14 @@ HandleFunctionRequest(StringInfo msgBuf)
if (aclresult != ACLCHECK_OK) if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, get_func_name(fid)); aclcheck_error(aclresult, get_func_name(fid));
/*
* Set up a query snapshot in case function needs one.
*/
SetQuerySnapshot();
/*
* Prepare function call info block.
*/
if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS) if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)", elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
nargs, fip->flinfo.fn_nargs); nargs, fip->flinfo.fn_nargs);
...@@ -359,12 +367,8 @@ HandleFunctionRequest(StringInfo msgBuf) ...@@ -359,12 +367,8 @@ HandleFunctionRequest(StringInfo msgBuf)
} }
} }
/* /* Verify we reached the end of the message where expected. */
* Set up a query snapshot in case function needs one. (It is not safe pq_getmsgend(msgBuf);
* to do this if we are in transaction-abort state, so we have to postpone
* it till now. Ugh.)
*/
SetQuerySnapshot();
#ifdef NO_FASTPATH #ifdef NO_FASTPATH
/* force a NULL return */ /* force a NULL return */
......
This diff is collapsed.
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.56 2003/05/02 20:54:35 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.57 2003/05/05 00:44:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -222,11 +222,12 @@ CreateNewPortal(void) ...@@ -222,11 +222,12 @@ CreateNewPortal(void)
* PortalDefineQuery * PortalDefineQuery
* A simple subroutine to establish a portal's query. * A simple subroutine to establish a portal's query.
* *
* Notes: the passed commandTag must be a pointer to a constant string, * Notes: commandTag shall be NULL if and only if the original query string
* since it is not copied. The caller is responsible for ensuring that * (before rewriting) was an empty string. Also, the passed commandTag must
* the passed sourceText (if any), parse and plan trees have adequate * be a pointer to a constant string, since it is not copied. The caller is
* lifetime. Also, queryContext must accurately describe the location * responsible for ensuring that the passed sourceText (if any), parse and
* of the parse and plan trees. * plan trees have adequate lifetime. Also, queryContext must accurately
* describe the location of the parse and plan trees.
*/ */
void void
PortalDefineQuery(Portal portal, PortalDefineQuery(Portal portal,
...@@ -241,6 +242,8 @@ PortalDefineQuery(Portal portal, ...@@ -241,6 +242,8 @@ PortalDefineQuery(Portal portal,
Assert(length(parseTrees) == length(planTrees)); Assert(length(parseTrees) == length(planTrees));
Assert(commandTag != NULL || parseTrees == NIL);
portal->sourceText = sourceText; portal->sourceText = sourceText;
portal->commandTag = commandTag; portal->commandTag = commandTag;
portal->parseTrees = parseTrees; portal->parseTrees = parseTrees;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: printtup.h,v 1.23 2003/01/21 22:06:12 tgl Exp $ * $Id: printtup.h,v 1.24 2003/05/05 00:44:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
#include "tcop/dest.h" #include "tcop/dest.h"
extern DestReceiver *printtup_create_DR(bool isBinary); extern DestReceiver *printtup_create_DR(bool isBinary, bool sendDescrip);
extern void SendRowDescriptionMessage(TupleDesc typeinfo);
extern void debugSetup(DestReceiver *self, int operation, extern void debugSetup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo); const char *portalName, TupleDesc typeinfo);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: portalcmds.h,v 1.8 2003/05/02 20:54:35 tgl Exp $ * $Id: portalcmds.h,v 1.9 2003/05/05 00:44:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -22,7 +22,7 @@ extern void PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest); ...@@ -22,7 +22,7 @@ extern void PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest);
extern void PerformPortalFetch(FetchStmt *stmt, CommandDest dest, extern void PerformPortalFetch(FetchStmt *stmt, CommandDest dest,
char *completionTag); char *completionTag);
extern void PerformPortalClose(char *name); extern void PerformPortalClose(const char *name);
extern void PortalCleanup(Portal portal, bool isError); extern void PortalCleanup(Portal portal, bool isError);
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* prepare.h * prepare.h
* PREPARE, EXECUTE and DEALLOCATE command prototypes * PREPARE, EXECUTE and DEALLOCATE commands, and prepared-stmt storage
* *
* *
* Copyright (c) 2002, PostgreSQL Global Development Group * Copyright (c) 2002-2003, PostgreSQL Global Development Group
* *
* $Id: prepare.h,v 1.3 2003/02/02 23:46:38 tgl Exp $ * $Id: prepare.h,v 1.4 2003/05/05 00:44:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,10 +18,44 @@ ...@@ -18,10 +18,44 @@
#include "tcop/dest.h" #include "tcop/dest.h"
/*
* The data structure representing a prepared statement
*
* Note: all subsidiary storage lives in the context denoted by the context
* field. However, the string referenced by commandTag is not subsidiary
* storage; it is assumed to be a compile-time-constant string. As with
* portals, commandTag shall be NULL if and only if the original query string
* (before rewriting) was an empty string.
*/
typedef struct
{
/* dynahash.c requires key to be first field */
char stmt_name[NAMEDATALEN];
char *query_string; /* text of query, or NULL */
const char *commandTag; /* command tag (a constant!), or NULL */
List *query_list; /* list of queries */
List *plan_list; /* list of plans */
List *argtype_list; /* list of parameter type OIDs */
MemoryContext context; /* context containing this query */
} PreparedStatement;
/* Utility statements PREPARE, EXECUTE, DEALLOCATE, EXPLAIN EXECUTE */
extern void PrepareQuery(PrepareStmt *stmt); extern void PrepareQuery(PrepareStmt *stmt);
extern void ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest); extern void ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest);
extern void DeallocateQuery(DeallocateStmt *stmt); extern void DeallocateQuery(DeallocateStmt *stmt);
extern List *FetchQueryParams(const char *plan_name);
extern void ExplainExecuteQuery(ExplainStmt *stmt, TupOutputState *tstate); extern void ExplainExecuteQuery(ExplainStmt *stmt, TupOutputState *tstate);
/* Low-level access to stored prepared statements */
extern void StorePreparedStatement(const char *stmt_name,
const char *query_string,
const char *commandTag,
List *query_list,
List *plan_list,
List *argtype_list);
extern PreparedStatement *FetchPreparedStatement(const char *stmt_name,
bool throwError);
extern void DropPreparedStatement(const char *stmt_name, bool showError);
extern List *FetchPreparedStatementParams(const char *stmt_name);
#endif /* PREPARE_H */ #endif /* PREPARE_H */
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pqcomm.h,v 1.81 2003/04/26 20:22:59 tgl Exp $ * $Id: pqcomm.h,v 1.82 2003/05/05 00:44:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -106,7 +106,7 @@ typedef union SockAddr ...@@ -106,7 +106,7 @@ typedef union SockAddr
/* The earliest and latest frontend/backend protocol version supported. */ /* The earliest and latest frontend/backend protocol version supported. */
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0) #define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0)
#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,105) /* XXX temporary value */ #define PG_PROTOCOL_LATEST PG_PROTOCOL(3,106) /* XXX temporary value */
typedef uint32 ProtocolVersion; /* FE/BE protocol version number */ typedef uint32 ProtocolVersion; /* FE/BE protocol version number */
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: dest.h,v 1.34 2003/04/19 00:02:30 tgl Exp $ * $Id: dest.h,v 1.35 2003/05/05 00:44:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -61,6 +61,10 @@ ...@@ -61,6 +61,10 @@
/* ---------------- /* ----------------
* CommandDest is a simplistic means of identifying the desired * CommandDest is a simplistic means of identifying the desired
* destination. Someday this will probably need to be improved. * destination. Someday this will probably need to be improved.
*
* Note: only the values None, Debug, Remote are legal for the global
* variable whereToSendOutput. The other values may be selected
* as the destination for individual commands.
* ---------------- * ----------------
*/ */
typedef enum typedef enum
...@@ -71,7 +75,9 @@ typedef enum ...@@ -71,7 +75,9 @@ typedef enum
RemoteInternal, /* results sent to frontend process in RemoteInternal, /* results sent to frontend process in
* internal (binary) form */ * internal (binary) form */
SPI, /* results sent to SPI manager */ SPI, /* results sent to SPI manager */
Tuplestore /* results sent to Tuplestore */ Tuplestore, /* results sent to Tuplestore */
RemoteExecute, /* sent to frontend, in Execute command */
RemoteExecuteInternal /* same, but binary format */
} CommandDest; } CommandDest;
/* ---------------- /* ----------------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: tcopprot.h,v 1.56 2003/05/02 20:54:36 tgl Exp $ * $Id: tcopprot.h,v 1.57 2003/05/05 00:44:56 tgl Exp $
* *
* OLD COMMENTS * OLD COMMENTS
* This file was created so that other c files could get the two * This file was created so that other c files could get the two
...@@ -35,11 +35,12 @@ extern DLLIMPORT const char *debug_query_string; ...@@ -35,11 +35,12 @@ extern DLLIMPORT const char *debug_query_string;
#ifndef BOOTSTRAP_INCLUDE #ifndef BOOTSTRAP_INCLUDE
extern List *pg_parse_and_rewrite(const char *query_string,
Oid *paramTypes, int numParams);
extern List *pg_parse_query(const char *query_string); extern List *pg_parse_query(const char *query_string);
extern List *pg_analyze_and_rewrite(Node *parsetree, extern List *pg_analyze_and_rewrite(Node *parsetree,
Oid *paramTypes, int numParams); Oid *paramTypes, int numParams);
extern List *pg_parse_and_rewrite(const char *query_string, extern List *pg_rewrite_queries(List *querytree_list);
Oid *paramTypes, int numParams);
extern Plan *pg_plan_query(Query *querytree); extern Plan *pg_plan_query(Query *querytree);
extern List *pg_plan_queries(List *querytrees, bool needSnapshot); extern List *pg_plan_queries(List *querytrees, bool needSnapshot);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.239 2003/04/28 04:52:13 tgl Exp $ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.240 2003/05/05 00:44:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -375,6 +375,17 @@ connectOptions1(PGconn *conn, const char *conninfo) ...@@ -375,6 +375,17 @@ connectOptions1(PGconn *conn, const char *conninfo)
static bool static bool
connectOptions2(PGconn *conn) connectOptions2(PGconn *conn)
{ {
/*
* If database name was not given, default it to equal user name
*/
if ((conn->dbName == NULL || conn->dbName[0] == '\0')
&& conn->pguser != NULL)
{
if (conn->dbName)
free(conn->dbName);
conn->dbName = strdup(conn->pguser);
}
/* /*
* Supply default password if none given * Supply default password if none given
*/ */
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: libpq-int.h,v 1.66 2003/04/26 20:23:00 tgl Exp $ * $Id: libpq-int.h,v 1.67 2003/05/05 00:44:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast ...@@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast
* pqcomm.h describe what the backend knows, not what libpq knows. * pqcomm.h describe what the backend knows, not what libpq knows.
*/ */
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,105) /* XXX temporary value */ #define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,106) /* XXX temporary value */
/* /*
* POSTGRES backend dependent Constants. * POSTGRES backend dependent Constants.
......
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