diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-05-08 18:16:37 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-05-08 18:16:37 +0000 |
commit | c0a8c3ac13f84602a46ba25b9a2fd5427514f61a (patch) | |
tree | f321719251471a05a768117f35010d28076f938a /src/backend/tcop/postgres.c | |
parent | 5e7a5c9511b65d483639dd3f7dfab7b9e92c3433 (diff) | |
download | postgresql-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.c | 207 |
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; |