diff options
Diffstat (limited to 'src/backend/tcop')
-rw-r--r-- | src/backend/tcop/dest.c | 37 | ||||
-rw-r--r-- | src/backend/tcop/fastpath.c | 260 | ||||
-rw-r--r-- | src/backend/tcop/postgres.c | 207 | ||||
-rw-r--r-- | src/backend/tcop/pquery.c | 82 |
4 files changed, 429 insertions, 157 deletions
diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c index bce77603f5b..a590cffd35a 100644 --- a/src/backend/tcop/dest.c +++ b/src/backend/tcop/dest.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.57 2003/05/06 20:26:27 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.58 2003/05/08 18:16:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -30,8 +30,10 @@ #include "access/printtup.h" #include "access/xact.h" +#include "executor/tstoreReceiver.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" +#include "utils/portal.h" /* ---------------- @@ -44,8 +46,7 @@ donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) } static void -donothingStartup(DestReceiver *self, int operation, - const char *portalName, TupleDesc typeinfo, List *targetlist) +donothingStartup(DestReceiver *self, int operation, TupleDesc typeinfo) { } @@ -90,18 +91,21 @@ BeginCommand(const char *commandTag, CommandDest dest) /* ---------------- * CreateDestReceiver - return appropriate receiver function set for dest + * + * Note: a Portal must be specified for destinations Remote, RemoteExecute, + * and Tuplestore. It can be NULL for the others. * ---------------- */ DestReceiver * -CreateDestReceiver(CommandDest dest) +CreateDestReceiver(CommandDest dest, Portal portal) { switch (dest) { case Remote: - case RemoteInternal: case RemoteExecute: - case RemoteExecuteInternal: - return printtup_create_DR(dest); + if (portal == NULL) + elog(ERROR, "CreateDestReceiver: no portal specified"); + return printtup_create_DR(dest, portal); case None: return &donothingDR; @@ -113,12 +117,13 @@ CreateDestReceiver(CommandDest dest) return &spi_printtupDR; case Tuplestore: - /* - * This is disallowed, you must use tstoreReceiver.c's - * specialized function to create a Tuplestore DestReceiver - */ - elog(ERROR, "CreateDestReceiver: cannot handle Tuplestore"); - break; + if (portal == NULL) + elog(ERROR, "CreateDestReceiver: no portal specified"); + if (portal->holdStore == NULL || + portal->holdContext == NULL) + elog(ERROR, "CreateDestReceiver: portal has no holdStore"); + return CreateTuplestoreDestReceiver(portal->holdStore, + portal->holdContext); } /* should never get here */ @@ -135,9 +140,7 @@ EndCommand(const char *commandTag, CommandDest dest) switch (dest) { case Remote: - case RemoteInternal: case RemoteExecute: - case RemoteExecuteInternal: pq_puttextmessage('C', commandTag); break; @@ -167,9 +170,7 @@ NullCommand(CommandDest dest) switch (dest) { case Remote: - case RemoteInternal: case RemoteExecute: - case RemoteExecuteInternal: /* * tell the fe that we saw an empty query string. In protocols @@ -206,9 +207,7 @@ ReadyForQuery(CommandDest dest) switch (dest) { case Remote: - case RemoteInternal: case RemoteExecute: - case RemoteExecuteInternal: if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) { StringInfoData buf; diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c index 65161c54ff3..0720f4e971d 100644 --- a/src/backend/tcop/fastpath.c +++ b/src/backend/tcop/fastpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.61 2003/05/05 00:44:56 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.62 2003/05/08 18:16:36 tgl Exp $ * * NOTES * This cruft is the server side of PQfn. @@ -47,6 +47,34 @@ #include "utils/tqual.h" +/* + * Formerly, this code attempted to cache the function and type info + * looked up by fetch_fp_info, but only for the duration of a single + * transaction command (since in theory the info could change between + * commands). This was utterly useless, because postgres.c executes + * each fastpath call as a separate transaction command, and so the + * cached data could never actually have been reused. If it had worked + * as intended, it would have had problems anyway with dangling references + * in the FmgrInfo struct. So, forget about caching and just repeat the + * syscache fetches on each usage. They're not *that* expensive. + */ +struct fp_info +{ + Oid funcid; + FmgrInfo flinfo; /* function lookup info for funcid */ + int16 arglen[FUNC_MAX_ARGS]; + bool argbyval[FUNC_MAX_ARGS]; + int16 retlen; + bool retbyval; +}; + + +static void parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip, + FunctionCallInfo fcinfo); +static void parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip, + FunctionCallInfo fcinfo); + + /* ---------------- * GetOldFunctionMessage * @@ -121,57 +149,73 @@ SendFunctionResult(Datum retval, bool retbyval, int retlen) pq_beginmessage(&buf, 'V'); - if (retlen != 0) + if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) { - pq_sendbyte(&buf, 'G'); - if (retbyval) - { /* by-value */ - pq_sendint(&buf, retlen, 4); - pq_sendint(&buf, DatumGetInt32(retval), retlen); + /* New-style message */ + /* XXX replace this with standard binary (or text!) output */ + if (retlen != 0) + { + if (retbyval) + { /* by-value */ + pq_sendint(&buf, retlen, 4); + pq_sendint(&buf, DatumGetInt32(retval), retlen); + } + else + { /* by-reference ... */ + if (retlen == -1) + { /* ... varlena */ + struct varlena *v = PG_DETOAST_DATUM(retval); + + pq_sendint(&buf, VARSIZE(v) - VARHDRSZ, VARHDRSZ); + pq_sendbytes(&buf, VARDATA(v), VARSIZE(v) - VARHDRSZ); + } + else + { /* ... fixed */ + pq_sendint(&buf, retlen, 4); + pq_sendbytes(&buf, DatumGetPointer(retval), retlen); + } + } } else - { /* by-reference ... */ - if (retlen == -1) - { /* ... varlena */ - struct varlena *v = PG_DETOAST_DATUM(retval); - - pq_sendint(&buf, VARSIZE(v) - VARHDRSZ, VARHDRSZ); - pq_sendbytes(&buf, VARDATA(v), VARSIZE(v) - VARHDRSZ); + { + /* NULL marker */ + pq_sendint(&buf, -1, 4); + } + } + else + { + /* Old-style message */ + if (retlen != 0) + { + pq_sendbyte(&buf, 'G'); + if (retbyval) + { /* by-value */ + pq_sendint(&buf, retlen, 4); + pq_sendint(&buf, DatumGetInt32(retval), retlen); } else - { /* ... fixed */ - pq_sendint(&buf, retlen, 4); - pq_sendbytes(&buf, DatumGetPointer(retval), retlen); + { /* by-reference ... */ + if (retlen == -1) + { /* ... varlena */ + struct varlena *v = PG_DETOAST_DATUM(retval); + + pq_sendint(&buf, VARSIZE(v) - VARHDRSZ, VARHDRSZ); + pq_sendbytes(&buf, VARDATA(v), VARSIZE(v) - VARHDRSZ); + } + else + { /* ... fixed */ + pq_sendint(&buf, retlen, 4); + pq_sendbytes(&buf, DatumGetPointer(retval), retlen); + } } } + pq_sendbyte(&buf, '0'); } - pq_sendbyte(&buf, '0'); pq_endmessage(&buf); } /* - * Formerly, this code attempted to cache the function and type info - * looked up by fetch_fp_info, but only for the duration of a single - * transaction command (since in theory the info could change between - * commands). This was utterly useless, because postgres.c executes - * each fastpath call as a separate transaction command, and so the - * cached data could never actually have been reused. If it had worked - * as intended, it would have had problems anyway with dangling references - * in the FmgrInfo struct. So, forget about caching and just repeat the - * syscache fetches on each usage. They're not *that* expensive. - */ -struct fp_info -{ - Oid funcid; - FmgrInfo flinfo; /* function lookup info for funcid */ - int16 arglen[FUNC_MAX_ARGS]; - bool argbyval[FUNC_MAX_ARGS]; - int16 retlen; - bool retbyval; -}; - -/* * fetch_fp_info * * Performs catalog lookups to load a struct fp_info 'fip' for the @@ -262,11 +306,9 @@ int HandleFunctionRequest(StringInfo msgBuf) { Oid fid; - int nargs; AclResult aclresult; FunctionCallInfoData fcinfo; Datum retval; - int i; struct fp_info my_fp; struct fp_info *fip; @@ -294,9 +336,10 @@ HandleFunctionRequest(StringInfo msgBuf) /* * Parse the buffer contents. */ - (void) pq_getmsgstring(msgBuf); /* dummy string */ + if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) + (void) pq_getmsgstring(msgBuf); /* dummy string */ + fid = (Oid) pq_getmsgint(msgBuf, 4); /* function oid */ - nargs = pq_getmsgint(msgBuf, 4); /* # of arguments */ /* * There used to be a lame attempt at caching lookup info here. Now we @@ -316,19 +359,61 @@ HandleFunctionRequest(StringInfo msgBuf) SetQuerySnapshot(); /* - * Prepare function call info block. + * Prepare function call info block and insert arguments. */ + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &fip->flinfo; + + if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) + parse_fcall_arguments(msgBuf, fip, &fcinfo); + else + parse_fcall_arguments_20(msgBuf, fip, &fcinfo); + + /* Verify we reached the end of the message where expected. */ + pq_getmsgend(msgBuf); + + /* Okay, do it ... */ + retval = FunctionCallInvoke(&fcinfo); + + if (fcinfo.isnull) + SendFunctionResult(retval, fip->retbyval, 0); + else + SendFunctionResult(retval, fip->retbyval, fip->retlen); + + return 0; +} + +/* + * Parse function arguments in a 3.0 protocol message + */ +static void +parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip, + FunctionCallInfo fcinfo) +{ + int nargs; + int i; + int numAFormats; + int16 *aformats = NULL; + + /* Get the argument format codes */ + numAFormats = pq_getmsgint(msgBuf, 2); + if (numAFormats > 0) + { + aformats = (int16 *) palloc(numAFormats * sizeof(int16)); + for (i = 0; i < numAFormats; i++) + aformats[i] = pq_getmsgint(msgBuf, 2); + } + + nargs = pq_getmsgint(msgBuf, 2); /* # of arguments */ + if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS) elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)", nargs, fip->flinfo.fn_nargs); - MemSet(&fcinfo, 0, sizeof(fcinfo)); - fcinfo.flinfo = &fip->flinfo; - fcinfo.nargs = nargs; + fcinfo->nargs = nargs; /* - * Copy supplied arguments into arg vector. Note there is no way for - * frontend to specify a NULL argument --- this protocol is misdesigned. + * Copy supplied arguments into arg vector. */ for (i = 0; i < nargs; ++i) { @@ -342,7 +427,7 @@ HandleFunctionRequest(StringInfo msgBuf) elog(ERROR, "HandleFunctionRequest: bogus argsize %d", argsize); /* XXX should we demand argsize == fip->arglen[i] ? */ - fcinfo.arg[i] = (Datum) pq_getmsgint(msgBuf, argsize); + fcinfo->arg[i] = (Datum) pq_getmsgint(msgBuf, argsize); } else { /* by-reference ... */ @@ -363,25 +448,70 @@ HandleFunctionRequest(StringInfo msgBuf) p = palloc(argsize + 1); /* +1 in case argsize is 0 */ pq_copymsgbytes(msgBuf, p, argsize); } - fcinfo.arg[i] = PointerGetDatum(p); + fcinfo->arg[i] = PointerGetDatum(p); } } - /* Verify we reached the end of the message where expected. */ - pq_getmsgend(msgBuf); + /* XXX for the moment, ignore result format code */ + (void) pq_getmsgint(msgBuf, 2); +} -#ifdef NO_FASTPATH - /* force a NULL return */ - retval = (Datum) 0; - fcinfo.isnull = true; -#else - retval = FunctionCallInvoke(&fcinfo); -#endif /* NO_FASTPATH */ +/* + * Parse function arguments in a 2.0 protocol message + */ +static void +parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip, + FunctionCallInfo fcinfo) +{ + int nargs; + int i; - if (fcinfo.isnull) - SendFunctionResult(retval, fip->retbyval, 0); - else - SendFunctionResult(retval, fip->retbyval, fip->retlen); + nargs = pq_getmsgint(msgBuf, 4); /* # of arguments */ - return 0; + if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS) + elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)", + nargs, fip->flinfo.fn_nargs); + + fcinfo->nargs = nargs; + + /* + * Copy supplied arguments into arg vector. Note there is no way for + * frontend to specify a NULL argument --- this protocol is misdesigned. + */ + for (i = 0; i < nargs; ++i) + { + int argsize; + char *p; + + argsize = pq_getmsgint(msgBuf, 4); + if (fip->argbyval[i]) + { /* by-value */ + if (argsize < 1 || argsize > 4) + elog(ERROR, "HandleFunctionRequest: bogus argsize %d", + argsize); + /* XXX should we demand argsize == fip->arglen[i] ? */ + fcinfo->arg[i] = (Datum) pq_getmsgint(msgBuf, argsize); + } + else + { /* by-reference ... */ + if (fip->arglen[i] == -1) + { /* ... varlena */ + if (argsize < 0) + elog(ERROR, "HandleFunctionRequest: bogus argsize %d", + argsize); + p = palloc(argsize + VARHDRSZ); + VARATT_SIZEP(p) = argsize + VARHDRSZ; + pq_copymsgbytes(msgBuf, VARDATA(p), argsize); + } + else + { /* ... fixed */ + if (argsize != fip->arglen[i]) + elog(ERROR, "HandleFunctionRequest: bogus argsize %d, should be %d", + argsize, fip->arglen[i]); + p = palloc(argsize + 1); /* +1 in case argsize is 0 */ + pq_copymsgbytes(msgBuf, p, argsize); + } + fcinfo->arg[i] = PointerGetDatum(p); + } + } } 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; diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index e3a37b7310e..bf63dcbc29c 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -8,14 +8,13 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.63 2003/05/06 21:01:04 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.64 2003/05/08 18:16:36 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "executor/executor.h" -#include "executor/tstoreReceiver.h" #include "miscadmin.h" #include "tcop/tcopprot.h" #include "tcop/pquery.h" @@ -47,7 +46,6 @@ QueryDesc * CreateQueryDesc(Query *parsetree, Plan *plantree, DestReceiver *dest, - const char *portalName, ParamListInfo params, bool doInstrument) { @@ -57,7 +55,6 @@ CreateQueryDesc(Query *parsetree, qd->parsetree = parsetree; /* parse tree */ qd->plantree = plantree; /* plan */ qd->dest = dest; /* output dest */ - qd->portalName = portalName; /* name, if dest is a portal */ qd->params = params; /* parameter values passed into query */ qd->doInstrument = doInstrument; /* instrumentation wanted? */ @@ -89,7 +86,6 @@ FreeQueryDesc(QueryDesc *qdesc) * parsetree: the query tree * plan: the plan tree for the query * params: any parameters needed - * portalName: name of portal being used * dest: where to send results * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE * in which to store a command completion status string. @@ -103,7 +99,6 @@ void ProcessQuery(Query *parsetree, Plan *plan, ParamListInfo params, - const char *portalName, DestReceiver *dest, char *completionTag) { @@ -131,8 +126,7 @@ ProcessQuery(Query *parsetree, /* * Create the QueryDesc object */ - queryDesc = CreateQueryDesc(parsetree, plan, dest, portalName, params, - false); + queryDesc = CreateQueryDesc(parsetree, plan, dest, params, false); /* * Call ExecStart to prepare the plan for execution @@ -269,7 +263,6 @@ PortalStart(Portal portal, ParamListInfo params) queryDesc = CreateQueryDesc((Query *) lfirst(portal->parseTrees), (Plan *) lfirst(portal->planTrees), None_Receiver, - portal->name, params, false); /* @@ -281,7 +274,7 @@ PortalStart(Portal portal, ParamListInfo params) */ portal->queryDesc = queryDesc; /* - * Remember tuple descriptor + * Remember tuple descriptor (computed by ExecutorStart) */ portal->tupDesc = queryDesc->tupDesc; /* @@ -321,6 +314,53 @@ PortalStart(Portal portal, ParamListInfo params) } /* + * PortalSetResultFormat + * Select the format codes for a portal's output. + * + * This must be run after PortalStart for a portal that will be read by + * a Remote or RemoteExecute destination. It is not presently needed for + * other destination types. + * + * formats[] is the client format request, as per Bind message conventions. + */ +void +PortalSetResultFormat(Portal portal, int nFormats, int16 *formats) +{ + int natts; + int i; + + /* Do nothing if portal won't return tuples */ + if (portal->tupDesc == NULL) + return; + natts = portal->tupDesc->natts; + /* +1 avoids palloc(0) if no columns */ + portal->formats = (int16 *) + MemoryContextAlloc(PortalGetHeapMemory(portal), + (natts + 1) * sizeof(int16)); + if (nFormats > 1) + { + /* format specified for each column */ + if (nFormats != natts) + elog(ERROR, "BIND message has %d result formats but query has %d columns", + nFormats, natts); + memcpy(portal->formats, formats, natts * sizeof(int16)); + } else if (nFormats > 0) + { + /* single format specified, use for all columns */ + int16 format1 = formats[0]; + + for (i = 0; i < natts; i++) + portal->formats[i] = format1; + } + else + { + /* use default format for all columns */ + for (i = 0; i < natts; i++) + portal->formats[i] = 0; + } +} + +/* * PortalRun * Run a portal's query or queries. * @@ -399,8 +439,7 @@ PortalRun(Portal portal, long count, DestReceiver *treceiver; PortalCreateHoldStore(portal); - treceiver = CreateTuplestoreDestReceiver(portal->holdStore, - portal->holdContext); + treceiver = CreateDestReceiver(Tuplestore, portal); PortalRunUtility(portal, lfirst(portal->parseTrees), treceiver, NULL); (*treceiver->destroy) (treceiver); @@ -604,16 +643,9 @@ static uint32 RunFromStore(Portal portal, ScanDirection direction, long count, DestReceiver *dest) { - List *targetlist; long current_tuple_count = 0; - if (portal->strategy == PORTAL_ONE_SELECT) - targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist; - else - targetlist = NIL; - - (*dest->startup) (dest, CMD_SELECT, portal->name, portal->tupDesc, - targetlist); + (*dest->startup) (dest, CMD_SELECT, portal->tupDesc); if (direction == NoMovementScanDirection) { @@ -737,11 +769,9 @@ PortalRunMulti(Portal portal, * but the results will be discarded unless you use "simple Query" * protocol. */ - if (dest->mydest == RemoteExecute || - dest->mydest == RemoteExecuteInternal) + if (dest->mydest == RemoteExecute) dest = None_Receiver; - if (altdest->mydest == RemoteExecute || - altdest->mydest == RemoteExecuteInternal) + if (altdest->mydest == RemoteExecute) altdest = None_Receiver; /* @@ -791,14 +821,14 @@ PortalRunMulti(Portal portal, { /* statement can set tag string */ ProcessQuery(query, plan, - portal->portalParams, portal->name, + portal->portalParams, dest, completionTag); } else { /* stmt added by rewrite cannot set tag */ ProcessQuery(query, plan, - portal->portalParams, portal->name, + portal->portalParams, altdest, NULL); } |