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:
@@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user