aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/postgres.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-05-08 18:16:37 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-05-08 18:16:37 +0000
commitc0a8c3ac13f84602a46ba25b9a2fd5427514f61a (patch)
treef321719251471a05a768117f35010d28076f938a /src/backend/tcop/postgres.c
parent5e7a5c9511b65d483639dd3f7dfab7b9e92c3433 (diff)
downloadpostgresql-c0a8c3ac13f84602a46ba25b9a2fd5427514f61a.tar.gz
postgresql-c0a8c3ac13f84602a46ba25b9a2fd5427514f61a.zip
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.
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r--src/backend/tcop/postgres.c207
1 files changed, 160 insertions, 47 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 89564558708..63b08dc969e 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -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;
@@ -686,12 +685,6 @@ exec_simple_query(const char *query_string)
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
* BEGIN/COMMIT/ABORT statement; we have to force a new xact command
@@ -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
@@ -804,11 +799,6 @@ exec_simple_query(const char *query_string)
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;
-
- getTypeInputInfo(ptype, &typInput, &typElem);
- params[i].value =
- OidFunctionCall3(typInput,
- CStringGetDatum(ptext),
- ObjectIdGetDatum(typElem),
- Int32GetDatum(-1));
+ int16 pformat;
+
+ 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);
/*
@@ -1278,6 +1383,11 @@ exec_bind_message(StringInfo input_message)
PortalStart(portal, params);
/*
+ * Apply the result format requests to the portal.
+ */
+ PortalSetResultFormat(portal, numRFormats, rformats);
+
+ /*
* Send BindComplete.
*/
if (whereToSendOutput == Remote)
@@ -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))
@@ -1353,6 +1463,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;