1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-13 18:28:01 +03:00

Update 3.0 protocol support to match recent agreements about how to

handle multiple 'formats' for data I/O.  Restructure CommandDest and
DestReceiver stuff one more time (it's finally starting to look a bit
clean though).  Code now matches latest 3.0 protocol document as far
as message formats go --- but there is no support for binary I/O yet.
This commit is contained in:
Tom Lane
2003-05-08 18:16:37 +00:00
parent 5e7a5c9511
commit c0a8c3ac13
24 changed files with 1003 additions and 684 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.339 2003/05/08 14:49:04 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.340 2003/05/08 18:16:36 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -658,7 +658,6 @@ static void
exec_simple_query(const char *query_string)
{
CommandDest dest = whereToSendOutput;
DestReceiver *receiver;
MemoryContext oldcontext;
List *parsetree_list,
*parsetree_item;
@@ -685,12 +684,6 @@ exec_simple_query(const char *query_string)
if (save_log_statement_stats)
ResetUsage();
/*
* Create destination receiver object --- we can reuse it for all
* queries in the string. Note it is created in MessageContext.
*/
receiver = CreateDestReceiver(dest);
/*
* Start up a transaction command. All queries generated by the
* query_string will be in this same command block, *unless* we find a
@@ -743,6 +736,8 @@ exec_simple_query(const char *query_string)
List *querytree_list,
*plantree_list;
Portal portal;
DestReceiver *receiver;
int16 format;
/*
* Get the command name for use in status display (it also becomes the
@@ -803,11 +798,6 @@ exec_simple_query(const char *query_string)
/* If we got a cancel signal in analysis or planning, quit */
CHECK_FOR_INTERRUPTS();
/*
* Switch back to transaction context for execution.
*/
MemoryContextSwitchTo(oldcontext);
/*
* Create unnamed portal to run the query or queries in.
* If there already is one, silently drop it.
@@ -822,16 +812,53 @@ exec_simple_query(const char *query_string)
MessageContext);
/*
* Run the portal to completion, and then drop it.
* Start the portal. No parameters here.
*/
PortalStart(portal, NULL);
/*
* Select the appropriate output format: text unless we are doing
* a FETCH from a binary cursor. (Pretty grotty to have to do this
* here --- but it avoids grottiness in other places. Ah, the joys
* of backward compatibility...)
*/
format = 0; /* TEXT is default */
if (IsA(parsetree, FetchStmt))
{
FetchStmt *stmt = (FetchStmt *) parsetree;
if (!stmt->ismove)
{
Portal fportal = GetPortalByName(stmt->portalname);
if (PortalIsValid(fportal) &&
(fportal->cursorOptions & CURSOR_OPT_BINARY))
format = 1; /* BINARY */
}
}
PortalSetResultFormat(portal, 1, &format);
/*
* Now we can create the destination receiver object.
*/
receiver = CreateDestReceiver(dest, portal);
/*
* Switch back to transaction context for execution.
*/
MemoryContextSwitchTo(oldcontext);
/*
* Run the portal to completion, and then drop it (and the receiver).
*/
(void) PortalRun(portal,
FETCH_ALL,
receiver,
receiver,
completionTag);
(*receiver->destroy) (receiver);
PortalDrop(portal, false);
@@ -886,8 +913,6 @@ exec_simple_query(const char *query_string)
if (!parsetree_list)
NullCommand(dest);
(*receiver->destroy) (receiver);
QueryContext = NULL;
/*
@@ -1156,8 +1181,12 @@ exec_bind_message(StringInfo input_message)
{
const char *portal_name;
const char *stmt_name;
int is_binary;
int numPFormats;
int16 *pformats = NULL;
int numParams;
int numRFormats;
int16 *rformats = NULL;
int i;
PreparedStatement *pstmt;
Portal portal;
ParamListInfo params;
@@ -1173,14 +1202,28 @@ exec_bind_message(StringInfo input_message)
*/
start_xact_command();
/* Switch back to message context */
MemoryContextSwitchTo(MessageContext);
/* Get the fixed part of the message */
portal_name = pq_getmsgstring(input_message);
stmt_name = pq_getmsgstring(input_message);
is_binary = pq_getmsgbyte(input_message);
numParams = pq_getmsgint(input_message, 4);
if (is_binary)
elog(ERROR, "Binary BIND not implemented yet");
/* Get the parameter format codes */
numPFormats = pq_getmsgint(input_message, 2);
if (numPFormats > 0)
{
pformats = (int16 *) palloc(numPFormats * sizeof(int16));
for (i = 0; i < numPFormats; i++)
pformats[i] = pq_getmsgint(input_message, 2);
}
/* Get the parameter value count */
numParams = pq_getmsgint(input_message, 2);
if (numPFormats > 1 && numPFormats != numParams)
elog(ERROR, "BIND message has %d parameter formats but %d parameters",
numPFormats, numParams);
/* Find prepared statement */
if (stmt_name[0] != '\0')
@@ -1217,45 +1260,98 @@ exec_bind_message(StringInfo input_message)
* Fetch parameters, if any, and store in the portal's memory context.
*
* In an aborted transaction, we can't risk calling user-defined functions,
* so bind all parameters to null values.
* but we can't fail to Bind either, so bind all parameters to null values.
*/
if (numParams > 0)
{
bool isaborted = IsAbortedTransactionBlockState();
int i = 0;
StringInfoData pbuf;
List *l;
MemoryContext oldContext;
/* Note that the string buffer lives in MessageContext */
initStringInfo(&pbuf);
oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
params = (ParamListInfo)
palloc0((numParams + 1) * sizeof(ParamListInfoData));
i = 0;
foreach(l, pstmt->argtype_list)
{
Oid ptype = lfirsto(l);
int32 plength;
bool isNull;
isNull = (pq_getmsgbyte(input_message) != 0) ? false : true;
plength = pq_getmsgint(input_message, 4);
isNull = (plength == -1);
if (!isNull)
{
const char *ptext = pq_getmsgstring(input_message);
/* Reset pbuf to empty, and insert raw data into it */
pbuf.len = 0;
pbuf.data[0] = '\0';
pbuf.cursor = 0;
appendBinaryStringInfo(&pbuf,
pq_getmsgbytes(input_message, plength),
plength);
if (isaborted)
{
/* We don't bother to check the format in this case */
isNull = true;
}
else
{
Oid typInput;
Oid typElem;
int16 pformat;
getTypeInputInfo(ptype, &typInput, &typElem);
params[i].value =
OidFunctionCall3(typInput,
CStringGetDatum(ptext),
ObjectIdGetDatum(typElem),
Int32GetDatum(-1));
if (numPFormats > 1)
pformat = pformats[i];
else if (numPFormats > 0)
pformat = pformats[0];
else
pformat = 0; /* default = text */
if (pformat == 0)
{
Oid typInput;
Oid typElem;
char *pstring;
getTypeInputInfo(ptype, &typInput, &typElem);
/*
* Since stringinfo.c keeps a trailing null in
* place even for binary data, the contents of
* pbuf are a valid C string. We have to do
* encoding conversion before calling the typinput
* routine, though.
*/
pstring = (char *)
pg_client_to_server((unsigned char *) pbuf.data,
plength);
params[i].value =
OidFunctionCall3(typInput,
CStringGetDatum(pstring),
ObjectIdGetDatum(typElem),
Int32GetDatum(-1));
/* Free result of encoding conversion, if any */
if (pstring != pbuf.data)
pfree(pstring);
}
else if (pformat == 1)
{
/* XXX something similar to above */
elog(ERROR, "Binary BIND not implemented yet");
}
else
{
elog(ERROR, "Invalid format code %d", pformat);
}
}
}
params[i].kind = PARAM_NUM;
params[i].id = i + 1;
params[i].isnull = isNull;
@@ -1270,6 +1366,15 @@ exec_bind_message(StringInfo input_message)
else
params = NULL;
/* Get the result format codes */
numRFormats = pq_getmsgint(input_message, 2);
if (numRFormats > 0)
{
rformats = (int16 *) palloc(numRFormats * sizeof(int16));
for (i = 0; i < numRFormats; i++)
rformats[i] = pq_getmsgint(input_message, 2);
}
pq_getmsgend(input_message);
/*
@@ -1277,6 +1382,11 @@ exec_bind_message(StringInfo input_message)
*/
PortalStart(portal, params);
/*
* Apply the result format requests to the portal.
*/
PortalSetResultFormat(portal, numRFormats, rformats);
/*
* Send BindComplete.
*/
@@ -1290,7 +1400,7 @@ exec_bind_message(StringInfo input_message)
* Process an "Execute" message for a portal
*/
static void
exec_execute_message(const char *portal_name, int is_binary, long max_rows)
exec_execute_message(const char *portal_name, long max_rows)
{
CommandDest dest;
DestReceiver *receiver;
@@ -1303,7 +1413,7 @@ exec_execute_message(const char *portal_name, int is_binary, long max_rows)
/* Adjust destination to tell printtup.c what to do */
dest = whereToSendOutput;
if (dest == Remote)
dest = is_binary ? RemoteExecuteInternal : RemoteExecute;
dest = RemoteExecute;
portal = GetPortalByName(portal_name);
if (!PortalIsValid(portal))
@@ -1352,6 +1462,12 @@ exec_execute_message(const char *portal_name, int is_binary, long max_rows)
}
}
/*
* Create dest receiver in MessageContext (we don't want it in transaction
* context, because that may get deleted if portal contains VACUUM).
*/
receiver = CreateDestReceiver(dest, portal);
/*
* Ensure we are in a transaction command (this should normally be
* the case already due to prior BIND).
@@ -1375,8 +1491,6 @@ exec_execute_message(const char *portal_name, int is_binary, long max_rows)
/*
* Okay to run the portal.
*/
receiver = CreateDestReceiver(dest);
if (max_rows <= 0)
max_rows = FETCH_ALL;
@@ -1451,7 +1565,7 @@ exec_describe_statement_message(const char *stmt_name)
* First describe the parameters...
*/
pq_beginmessage(&buf, 't'); /* parameter description message type */
pq_sendint(&buf, length(pstmt->argtype_list), 4);
pq_sendint(&buf, length(pstmt->argtype_list), 2);
foreach(l, pstmt->argtype_list)
{
@@ -1473,7 +1587,7 @@ exec_describe_statement_message(const char *stmt_name)
targetlist = ((Query *) lfirst(pstmt->query_list))->targetList;
else
targetlist = NIL;
SendRowDescriptionMessage(tupdesc, targetlist);
SendRowDescriptionMessage(tupdesc, targetlist, NULL);
}
else
pq_putemptymessage('n'); /* NoData */
@@ -1502,10 +1616,11 @@ exec_describe_portal_message(const char *portal_name)
List *targetlist;
if (portal->strategy == PORTAL_ONE_SELECT)
targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist;
targetlist = ((Query *) lfirst(portal->parseTrees))->targetList;
else
targetlist = NIL;
SendRowDescriptionMessage(portal->tupDesc, targetlist);
SendRowDescriptionMessage(portal->tupDesc, targetlist,
portal->formats);
}
else
pq_putemptymessage('n'); /* NoData */
@@ -2397,7 +2512,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.339 $ $Date: 2003/05/08 14:49:04 $\n");
puts("$Revision: 1.340 $ $Date: 2003/05/08 18:16:36 $\n");
}
/*
@@ -2613,7 +2728,7 @@ PostgresMain(int argc, char *argv[], const char *username)
stmt_name = pq_getmsgstring(input_message);
query_string = pq_getmsgstring(input_message);
numParams = pq_getmsgint(input_message, 4);
numParams = pq_getmsgint(input_message, 2);
if (numParams > 0)
{
int i;
@@ -2640,15 +2755,13 @@ PostgresMain(int argc, char *argv[], const char *username)
case 'E': /* execute */
{
const char *portal_name;
int is_binary;
int max_rows;
portal_name = pq_getmsgstring(input_message);
is_binary = pq_getmsgbyte(input_message);
max_rows = pq_getmsgint(input_message, 4);
pq_getmsgend(input_message);
exec_execute_message(portal_name, is_binary, max_rows);
exec_execute_message(portal_name, max_rows);
}
break;