Commit c0a8c3ac authored by Tom Lane's avatar Tom Lane

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.
parent 5e7a5c95
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.197 2003/04/25 02:28:22 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.198 2003/05/08 18:16:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -125,8 +125,8 @@ static int server_encoding; ...@@ -125,8 +125,8 @@ static int server_encoding;
/* /*
* Internal communications functions * Internal communications functions
*/ */
static void SendCopyBegin(bool binary); static void SendCopyBegin(bool binary, int natts);
static void ReceiveCopyBegin(bool binary); static void ReceiveCopyBegin(bool binary, int natts);
static void SendCopyEnd(bool binary); static void SendCopyEnd(bool binary);
static void CopySendData(void *databuf, int datasize); static void CopySendData(void *databuf, int datasize);
static void CopySendString(const char *str); static void CopySendString(const char *str);
...@@ -143,15 +143,20 @@ static void CopyDonePeek(int c, bool pickup); ...@@ -143,15 +143,20 @@ static void CopyDonePeek(int c, bool pickup);
* in past protocol redesigns. * in past protocol redesigns.
*/ */
static void static void
SendCopyBegin(bool binary) SendCopyBegin(bool binary, int natts)
{ {
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{ {
/* new way */ /* new way */
StringInfoData buf; StringInfoData buf;
int16 format = (binary ? 1 : 0);
int i;
pq_beginmessage(&buf, 'H'); pq_beginmessage(&buf, 'H');
pq_sendbyte(&buf, binary ? 1 : 0); pq_sendbyte(&buf, format); /* overall format */
pq_sendint(&buf, natts, 2);
for (i = 0; i < natts; i++)
pq_sendint(&buf, format, 2); /* per-column formats */
pq_endmessage(&buf); pq_endmessage(&buf);
copy_dest = COPY_NEW_FE; copy_dest = COPY_NEW_FE;
copy_msgbuf = makeStringInfo(); copy_msgbuf = makeStringInfo();
...@@ -179,15 +184,20 @@ SendCopyBegin(bool binary) ...@@ -179,15 +184,20 @@ SendCopyBegin(bool binary)
} }
static void static void
ReceiveCopyBegin(bool binary) ReceiveCopyBegin(bool binary, int natts)
{ {
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{ {
/* new way */ /* new way */
StringInfoData buf; StringInfoData buf;
int16 format = (binary ? 1 : 0);
int i;
pq_beginmessage(&buf, 'G'); pq_beginmessage(&buf, 'G');
pq_sendbyte(&buf, binary ? 1 : 0); pq_sendbyte(&buf, format); /* overall format */
pq_sendint(&buf, natts, 2);
for (i = 0; i < natts; i++)
pq_sendint(&buf, format, 2); /* per-column formats */
pq_endmessage(&buf); pq_endmessage(&buf);
copy_dest = COPY_NEW_FE; copy_dest = COPY_NEW_FE;
copy_msgbuf = makeStringInfo(); copy_msgbuf = makeStringInfo();
...@@ -682,7 +692,7 @@ DoCopy(const CopyStmt *stmt) ...@@ -682,7 +692,7 @@ DoCopy(const CopyStmt *stmt)
if (pipe) if (pipe)
{ {
if (IsUnderPostmaster) if (IsUnderPostmaster)
ReceiveCopyBegin(binary); ReceiveCopyBegin(binary, length(attnumlist));
else else
copy_file = stdin; copy_file = stdin;
} }
...@@ -724,7 +734,7 @@ DoCopy(const CopyStmt *stmt) ...@@ -724,7 +734,7 @@ DoCopy(const CopyStmt *stmt)
if (pipe) if (pipe)
{ {
if (IsUnderPostmaster) if (IsUnderPostmaster)
SendCopyBegin(binary); SendCopyBegin(binary, length(attnumlist));
else else
copy_file = stdout; copy_file = stdout;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.108 2003/05/06 20:26:26 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.109 2003/05/08 18:16:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -179,7 +179,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate) ...@@ -179,7 +179,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
plan = planner(query, isCursor, cursorOptions); plan = planner(query, isCursor, cursorOptions);
/* Create a QueryDesc requesting no output */ /* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL, NULL, queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL,
stmt->analyze); stmt->analyze);
ExplainOnePlan(queryDesc, stmt, tstate); ExplainOnePlan(queryDesc, stmt, tstate);
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.15 2003/05/06 20:26:26 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.16 2003/05/08 18:16:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include "commands/portalcmds.h" #include "commands/portalcmds.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "executor/tstoreReceiver.h"
#include "optimizer/planner.h" #include "optimizer/planner.h"
#include "rewrite/rewriteHandler.h" #include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h" #include "tcop/pquery.h"
...@@ -145,7 +144,6 @@ PerformPortalFetch(FetchStmt *stmt, ...@@ -145,7 +144,6 @@ PerformPortalFetch(FetchStmt *stmt,
DestReceiver *dest, DestReceiver *dest,
char *completionTag) char *completionTag)
{ {
DestReceiver *mydest = dest;
Portal portal; Portal portal;
long nprocessed; long nprocessed;
...@@ -168,35 +166,21 @@ PerformPortalFetch(FetchStmt *stmt, ...@@ -168,35 +166,21 @@ PerformPortalFetch(FetchStmt *stmt,
return; return;
} }
/* /* Adjust dest if needed. MOVE wants destination None */
* Adjust dest if needed. MOVE wants destination None.
*
* If fetching from a binary cursor and the requested destination is
* Remote, change it to RemoteInternal. Note we do NOT change if the
* destination is RemoteExecute --- so the Execute message's format
* specification wins out over the cursor's type.
*/
if (stmt->ismove) if (stmt->ismove)
mydest = CreateDestReceiver(None); dest = None_Receiver;
else if (dest->mydest == Remote &&
(portal->cursorOptions & CURSOR_OPT_BINARY))
mydest = CreateDestReceiver(RemoteInternal);
/* Do it */ /* Do it */
nprocessed = PortalRunFetch(portal, nprocessed = PortalRunFetch(portal,
stmt->direction, stmt->direction,
stmt->howMany, stmt->howMany,
mydest); dest);
/* Return command status if wanted */ /* Return command status if wanted */
if (completionTag) if (completionTag)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld", snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld",
stmt->ismove ? "MOVE" : "FETCH", stmt->ismove ? "MOVE" : "FETCH",
nprocessed); nprocessed);
/* Clean up if we created a local destination */
if (mydest != dest)
(mydest->destroy) (mydest);
} }
/* /*
...@@ -329,8 +313,7 @@ PersistHoldablePortal(Portal portal) ...@@ -329,8 +313,7 @@ PersistHoldablePortal(Portal portal)
ExecutorRewind(queryDesc); ExecutorRewind(queryDesc);
/* Change the destination to output to the tuplestore */ /* Change the destination to output to the tuplestore */
queryDesc->dest = CreateTuplestoreDestReceiver(portal->holdStore, queryDesc->dest = CreateDestReceiver(Tuplestore, portal);
portal->holdContext);
/* Fetch the result set into the tuplestore */ /* Fetch the result set into the tuplestore */
ExecutorRun(queryDesc, ForwardScanDirection, 0L); ExecutorRun(queryDesc, ForwardScanDirection, 0L);
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Copyright (c) 2002-2003, PostgreSQL Global Development Group * Copyright (c) 2002-2003, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.17 2003/05/06 21:51:41 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.18 2003/05/08 18:16:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -528,7 +528,7 @@ ExplainExecuteQuery(ExplainStmt *stmt, TupOutputState *tstate) ...@@ -528,7 +528,7 @@ ExplainExecuteQuery(ExplainStmt *stmt, TupOutputState *tstate)
} }
/* Create a QueryDesc requesting no output */ /* Create a QueryDesc requesting no output */
qdesc = CreateQueryDesc(query, plan, None_Receiver, NULL, qdesc = CreateQueryDesc(query, plan, None_Receiver,
paramLI, stmt->analyze); paramLI, stmt->analyze);
ExplainOnePlan(qdesc, stmt, tstate); ExplainOnePlan(qdesc, stmt, tstate);
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.208 2003/05/06 20:26:26 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.209 2003/05/08 18:16:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -217,10 +217,7 @@ ExecutorRun(QueryDesc *queryDesc, ...@@ -217,10 +217,7 @@ ExecutorRun(QueryDesc *queryDesc,
estate->es_processed = 0; estate->es_processed = 0;
estate->es_lastoid = InvalidOid; estate->es_lastoid = InvalidOid;
(*dest->startup) (dest, operation, (*dest->startup) (dest, operation, queryDesc->tupDesc);
queryDesc->portalName,
queryDesc->tupDesc,
queryDesc->planstate->plan->targetlist);
/* /*
* run plan * run plan
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.65 2003/05/06 20:26:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.66 2003/05/08 18:16:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -765,8 +765,7 @@ begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc) ...@@ -765,8 +765,7 @@ begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc)
tstate->metadata = TupleDescGetAttInMetadata(tupdesc); tstate->metadata = TupleDescGetAttInMetadata(tupdesc);
tstate->dest = dest; tstate->dest = dest;
(*tstate->dest->startup) (tstate->dest, (int) CMD_SELECT, (*tstate->dest->startup) (tstate->dest, (int) CMD_SELECT, tupdesc);
NULL, tupdesc, NIL);
return tstate; return tstate;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.64 2003/05/06 20:26:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.65 2003/05/08 18:16:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -245,7 +245,7 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache) ...@@ -245,7 +245,7 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
{ {
Assert(es->qd == NULL); Assert(es->qd == NULL);
es->qd = CreateQueryDesc(es->query, es->plan, es->qd = CreateQueryDesc(es->query, es->plan,
None_Receiver, NULL, None_Receiver,
fcache->paramLI, false); fcache->paramLI, false);
/* Utility commands don't need Executor. */ /* Utility commands don't need Executor. */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.96 2003/05/06 20:26:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.97 2003/05/08 18:16:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -841,7 +841,8 @@ SPI_cursor_find(const char *name) ...@@ -841,7 +841,8 @@ SPI_cursor_find(const char *name)
void void
SPI_cursor_fetch(Portal portal, bool forward, int count) SPI_cursor_fetch(Portal portal, bool forward, int count)
{ {
_SPI_cursor_operation(portal, forward, count, CreateDestReceiver(SPI)); _SPI_cursor_operation(portal, forward, count,
CreateDestReceiver(SPI, NULL));
/* we know that the SPI receiver doesn't need a destroy call */ /* we know that the SPI receiver doesn't need a destroy call */
} }
...@@ -880,8 +881,7 @@ SPI_cursor_close(Portal portal) ...@@ -880,8 +881,7 @@ SPI_cursor_close(Portal portal)
* of current SPI procedure * of current SPI procedure
*/ */
void void
spi_dest_startup(DestReceiver *self, int operation, spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
const char *portalName, TupleDesc typeinfo, List *targetlist)
{ {
SPITupleTable *tuptable; SPITupleTable *tuptable;
MemoryContext oldcxt; MemoryContext oldcxt;
...@@ -1035,7 +1035,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan) ...@@ -1035,7 +1035,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
planTree = pg_plan_query(queryTree); planTree = pg_plan_query(queryTree);
plan_list = lappend(plan_list, planTree); plan_list = lappend(plan_list, planTree);
dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None); dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None, NULL);
if (queryTree->commandType == CMD_UTILITY) if (queryTree->commandType == CMD_UTILITY)
{ {
if (IsA(queryTree->utilityStmt, CopyStmt)) if (IsA(queryTree->utilityStmt, CopyStmt))
...@@ -1061,7 +1061,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan) ...@@ -1061,7 +1061,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
else if (plan == NULL) else if (plan == NULL)
{ {
qdesc = CreateQueryDesc(queryTree, planTree, dest, qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL, NULL, false); NULL, false);
res = _SPI_pquery(qdesc, true, res = _SPI_pquery(qdesc, true,
queryTree->canSetTag ? tcount : 0); queryTree->canSetTag ? tcount : 0);
if (res < 0) if (res < 0)
...@@ -1071,7 +1071,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan) ...@@ -1071,7 +1071,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
else else
{ {
qdesc = CreateQueryDesc(queryTree, planTree, dest, qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL, NULL, false); NULL, false);
res = _SPI_pquery(qdesc, false, 0); res = _SPI_pquery(qdesc, false, 0);
if (res < 0) if (res < 0)
return res; return res;
...@@ -1150,7 +1150,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, ...@@ -1150,7 +1150,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
planTree = lfirst(plan_list); planTree = lfirst(plan_list);
plan_list = lnext(plan_list); plan_list = lnext(plan_list);
dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None); dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None, NULL);
if (queryTree->commandType == CMD_UTILITY) if (queryTree->commandType == CMD_UTILITY)
{ {
ProcessUtility(queryTree->utilityStmt, dest, NULL); ProcessUtility(queryTree->utilityStmt, dest, NULL);
...@@ -1160,7 +1160,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, ...@@ -1160,7 +1160,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
else else
{ {
qdesc = CreateQueryDesc(queryTree, planTree, dest, qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL, paramLI, false); paramLI, false);
res = _SPI_pquery(qdesc, true, res = _SPI_pquery(qdesc, true,
queryTree->canSetTag ? tcount : 0); queryTree->canSetTag ? tcount : 0);
if (res < 0) if (res < 0)
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.5 2003/05/06 20:26:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.6 2003/05/08 18:16:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -31,9 +31,7 @@ typedef struct ...@@ -31,9 +31,7 @@ typedef struct
* Prepare to receive tuples from executor. * Prepare to receive tuples from executor.
*/ */
static void static void
tstoreStartupReceiver(DestReceiver *self, int operation, tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
const char *portalname,
TupleDesc typeinfo, List *targetlist)
{ {
/* do nothing */ /* do nothing */
} }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.28 2003/04/22 00:08:06 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.29 2003/05/08 18:16:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -104,27 +104,32 @@ pq_sendbytes(StringInfo buf, const char *data, int datalen) ...@@ -104,27 +104,32 @@ pq_sendbytes(StringInfo buf, const char *data, int datalen)
* pq_sendcountedtext - append a text string (with character set conversion) * pq_sendcountedtext - append a text string (with character set conversion)
* *
* The data sent to the frontend by this routine is a 4-byte count field * The data sent to the frontend by this routine is a 4-byte count field
* (the count includes itself, by convention) followed by the string. * followed by the string. The count includes itself or not, as per the
* countincludesself flag (pre-3.0 protocol requires it to include itself).
* The passed text string need not be null-terminated, and the data sent * The passed text string need not be null-terminated, and the data sent
* to the frontend isn't either. * to the frontend isn't either.
* -------------------------------- * --------------------------------
*/ */
void void
pq_sendcountedtext(StringInfo buf, const char *str, int slen) pq_sendcountedtext(StringInfo buf, const char *str, int slen,
bool countincludesself)
{ {
int extra = countincludesself ? 4 : 0;
char *p; char *p;
p = (char *) pg_server_to_client((unsigned char *) str, slen); p = (char *) pg_server_to_client((unsigned char *) str, slen);
if (p != str) /* actual conversion has been done? */ if (p != str) /* actual conversion has been done? */
{ {
slen = strlen(p); slen = strlen(p);
pq_sendint(buf, slen + 4, 4); pq_sendint(buf, slen + extra, 4);
appendBinaryStringInfo(buf, p, slen); appendBinaryStringInfo(buf, p, slen);
pfree(p); pfree(p);
return;
} }
pq_sendint(buf, slen + 4, 4); else
appendBinaryStringInfo(buf, str, slen); {
pq_sendint(buf, slen + extra, 4);
appendBinaryStringInfo(buf, str, slen);
}
} }
/* -------------------------------- /* --------------------------------
...@@ -296,7 +301,7 @@ pq_getmsgbytes(StringInfo msg, int datalen) ...@@ -296,7 +301,7 @@ pq_getmsgbytes(StringInfo msg, int datalen)
{ {
const char *result; const char *result;
if (datalen > (msg->len - msg->cursor)) if (datalen < 0 || datalen > (msg->len - msg->cursor))
elog(ERROR, "pq_getmsgbytes: insufficient data left in message"); elog(ERROR, "pq_getmsgbytes: insufficient data left in message");
result = &msg->data[msg->cursor]; result = &msg->data[msg->cursor];
msg->cursor += datalen; msg->cursor += datalen;
...@@ -312,7 +317,7 @@ pq_getmsgbytes(StringInfo msg, int datalen) ...@@ -312,7 +317,7 @@ pq_getmsgbytes(StringInfo msg, int datalen)
void void
pq_copymsgbytes(StringInfo msg, char *buf, int datalen) pq_copymsgbytes(StringInfo msg, char *buf, int datalen)
{ {
if (datalen > (msg->len - msg->cursor)) if (datalen < 0 || datalen > (msg->len - msg->cursor))
elog(ERROR, "pq_copymsgbytes: insufficient data left in message"); elog(ERROR, "pq_copymsgbytes: insufficient data left in message");
memcpy(buf, &msg->data[msg->cursor], datalen); memcpy(buf, &msg->data[msg->cursor], datalen);
msg->cursor += datalen; msg->cursor += datalen;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 @@ ...@@ -30,8 +30,10 @@
#include "access/printtup.h" #include "access/printtup.h"
#include "access/xact.h" #include "access/xact.h"
#include "executor/tstoreReceiver.h"
#include "libpq/libpq.h" #include "libpq/libpq.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "utils/portal.h"
/* ---------------- /* ----------------
...@@ -44,8 +46,7 @@ donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) ...@@ -44,8 +46,7 @@ donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
} }
static void static void
donothingStartup(DestReceiver *self, int operation, donothingStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
const char *portalName, TupleDesc typeinfo, List *targetlist)
{ {
} }
...@@ -90,18 +91,21 @@ BeginCommand(const char *commandTag, CommandDest dest) ...@@ -90,18 +91,21 @@ BeginCommand(const char *commandTag, CommandDest dest)
/* ---------------- /* ----------------
* CreateDestReceiver - return appropriate receiver function set for 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 * DestReceiver *
CreateDestReceiver(CommandDest dest) CreateDestReceiver(CommandDest dest, Portal portal)
{ {
switch (dest) switch (dest)
{ {
case Remote: case Remote:
case RemoteInternal:
case RemoteExecute: case RemoteExecute:
case RemoteExecuteInternal: if (portal == NULL)
return printtup_create_DR(dest); elog(ERROR, "CreateDestReceiver: no portal specified");
return printtup_create_DR(dest, portal);
case None: case None:
return &donothingDR; return &donothingDR;
...@@ -113,12 +117,13 @@ CreateDestReceiver(CommandDest dest) ...@@ -113,12 +117,13 @@ CreateDestReceiver(CommandDest dest)
return &spi_printtupDR; return &spi_printtupDR;
case Tuplestore: case Tuplestore:
/* if (portal == NULL)
* This is disallowed, you must use tstoreReceiver.c's elog(ERROR, "CreateDestReceiver: no portal specified");
* specialized function to create a Tuplestore DestReceiver if (portal->holdStore == NULL ||
*/ portal->holdContext == NULL)
elog(ERROR, "CreateDestReceiver: cannot handle Tuplestore"); elog(ERROR, "CreateDestReceiver: portal has no holdStore");
break; return CreateTuplestoreDestReceiver(portal->holdStore,
portal->holdContext);
} }
/* should never get here */ /* should never get here */
...@@ -135,9 +140,7 @@ EndCommand(const char *commandTag, CommandDest dest) ...@@ -135,9 +140,7 @@ EndCommand(const char *commandTag, CommandDest dest)
switch (dest) switch (dest)
{ {
case Remote: case Remote:
case RemoteInternal:
case RemoteExecute: case RemoteExecute:
case RemoteExecuteInternal:
pq_puttextmessage('C', commandTag); pq_puttextmessage('C', commandTag);
break; break;
...@@ -167,9 +170,7 @@ NullCommand(CommandDest dest) ...@@ -167,9 +170,7 @@ NullCommand(CommandDest dest)
switch (dest) switch (dest)
{ {
case Remote: case Remote:
case RemoteInternal:
case RemoteExecute: case RemoteExecute:
case RemoteExecuteInternal:
/* /*
* tell the fe that we saw an empty query string. In protocols * tell the fe that we saw an empty query string. In protocols
...@@ -206,9 +207,7 @@ ReadyForQuery(CommandDest dest) ...@@ -206,9 +207,7 @@ ReadyForQuery(CommandDest dest)
switch (dest) switch (dest)
{ {
case Remote: case Remote:
case RemoteInternal:
case RemoteExecute: case RemoteExecute:
case RemoteExecuteInternal:
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{ {
StringInfoData buf; StringInfoData buf;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* This cruft is the server side of PQfn. * This cruft is the server side of PQfn.
...@@ -47,6 +47,34 @@ ...@@ -47,6 +47,34 @@
#include "utils/tqual.h" #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 * GetOldFunctionMessage
* *
...@@ -121,56 +149,72 @@ SendFunctionResult(Datum retval, bool retbyval, int retlen) ...@@ -121,56 +149,72 @@ SendFunctionResult(Datum retval, bool retbyval, int retlen)
pq_beginmessage(&buf, 'V'); pq_beginmessage(&buf, 'V');
if (retlen != 0) if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
{ {
pq_sendbyte(&buf, 'G'); /* New-style message */
if (retbyval) /* XXX replace this with standard binary (or text!) output */
{ /* by-value */ if (retlen != 0)
pq_sendint(&buf, retlen, 4); {
pq_sendint(&buf, DatumGetInt32(retval), retlen); 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 else
{ /* by-reference ... */ {
if (retlen == -1) /* NULL marker */
{ /* ... varlena */ pq_sendint(&buf, -1, 4);
struct varlena *v = PG_DETOAST_DATUM(retval); }
}
pq_sendint(&buf, VARSIZE(v) - VARHDRSZ, VARHDRSZ); else
pq_sendbytes(&buf, VARDATA(v), VARSIZE(v) - VARHDRSZ); {
/* 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 else
{ /* ... fixed */ { /* by-reference ... */
pq_sendint(&buf, retlen, 4); if (retlen == -1)
pq_sendbytes(&buf, DatumGetPointer(retval), retlen); { /* ... 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); 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 * fetch_fp_info
* *
...@@ -262,11 +306,9 @@ int ...@@ -262,11 +306,9 @@ int
HandleFunctionRequest(StringInfo msgBuf) HandleFunctionRequest(StringInfo msgBuf)
{ {
Oid fid; Oid fid;
int nargs;
AclResult aclresult; AclResult aclresult;
FunctionCallInfoData fcinfo; FunctionCallInfoData fcinfo;
Datum retval; Datum retval;
int i;
struct fp_info my_fp; struct fp_info my_fp;
struct fp_info *fip; struct fp_info *fip;
...@@ -294,9 +336,10 @@ HandleFunctionRequest(StringInfo msgBuf) ...@@ -294,9 +336,10 @@ HandleFunctionRequest(StringInfo msgBuf)
/* /*
* Parse the buffer contents. * 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 */ 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 * There used to be a lame attempt at caching lookup info here. Now we
...@@ -316,19 +359,61 @@ HandleFunctionRequest(StringInfo msgBuf) ...@@ -316,19 +359,61 @@ HandleFunctionRequest(StringInfo msgBuf)
SetQuerySnapshot(); 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) if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)", elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
nargs, fip->flinfo.fn_nargs); nargs, fip->flinfo.fn_nargs);
MemSet(&fcinfo, 0, sizeof(fcinfo)); fcinfo->nargs = nargs;
fcinfo.flinfo = &fip->flinfo;
fcinfo.nargs = nargs;
/* /*
* Copy supplied arguments into arg vector. Note there is no way for * Copy supplied arguments into arg vector.
* frontend to specify a NULL argument --- this protocol is misdesigned.
*/ */
for (i = 0; i < nargs; ++i) for (i = 0; i < nargs; ++i)
{ {
...@@ -342,7 +427,7 @@ HandleFunctionRequest(StringInfo msgBuf) ...@@ -342,7 +427,7 @@ HandleFunctionRequest(StringInfo msgBuf)
elog(ERROR, "HandleFunctionRequest: bogus argsize %d", elog(ERROR, "HandleFunctionRequest: bogus argsize %d",
argsize); argsize);
/* XXX should we demand argsize == fip->arglen[i] ? */ /* 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 else
{ /* by-reference ... */ { /* by-reference ... */
...@@ -363,25 +448,70 @@ HandleFunctionRequest(StringInfo msgBuf) ...@@ -363,25 +448,70 @@ HandleFunctionRequest(StringInfo msgBuf)
p = palloc(argsize + 1); /* +1 in case argsize is 0 */ p = palloc(argsize + 1); /* +1 in case argsize is 0 */
pq_copymsgbytes(msgBuf, p, argsize); 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. */ /* XXX for the moment, ignore result format code */
pq_getmsgend(msgBuf); (void) pq_getmsgint(msgBuf, 2);
}
#ifdef NO_FASTPATH /*
/* force a NULL return */ * Parse function arguments in a 2.0 protocol message
retval = (Datum) 0; */
fcinfo.isnull = true; static void
#else parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip,
retval = FunctionCallInvoke(&fcinfo); FunctionCallInfo fcinfo)
#endif /* NO_FASTPATH */ {
int nargs;
int i;
if (fcinfo.isnull) nargs = pq_getmsgint(msgBuf, 4); /* # of arguments */
SendFunctionResult(retval, fip->retbyval, 0);
else
SendFunctionResult(retval, fip->retbyval, fip->retlen);
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);
}
}
} }
This diff is collapsed.
...@@ -8,14 +8,13 @@ ...@@ -8,14 +8,13 @@
* *
* *
* IDENTIFICATION * 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 "postgres.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "executor/tstoreReceiver.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
#include "tcop/pquery.h" #include "tcop/pquery.h"
...@@ -47,7 +46,6 @@ QueryDesc * ...@@ -47,7 +46,6 @@ QueryDesc *
CreateQueryDesc(Query *parsetree, CreateQueryDesc(Query *parsetree,
Plan *plantree, Plan *plantree,
DestReceiver *dest, DestReceiver *dest,
const char *portalName,
ParamListInfo params, ParamListInfo params,
bool doInstrument) bool doInstrument)
{ {
...@@ -57,7 +55,6 @@ CreateQueryDesc(Query *parsetree, ...@@ -57,7 +55,6 @@ CreateQueryDesc(Query *parsetree,
qd->parsetree = parsetree; /* parse tree */ qd->parsetree = parsetree; /* parse tree */
qd->plantree = plantree; /* plan */ qd->plantree = plantree; /* plan */
qd->dest = dest; /* output dest */ qd->dest = dest; /* output dest */
qd->portalName = portalName; /* name, if dest is a portal */
qd->params = params; /* parameter values passed into query */ qd->params = params; /* parameter values passed into query */
qd->doInstrument = doInstrument; /* instrumentation wanted? */ qd->doInstrument = doInstrument; /* instrumentation wanted? */
...@@ -89,7 +86,6 @@ FreeQueryDesc(QueryDesc *qdesc) ...@@ -89,7 +86,6 @@ FreeQueryDesc(QueryDesc *qdesc)
* parsetree: the query tree * parsetree: the query tree
* plan: the plan tree for the query * plan: the plan tree for the query
* params: any parameters needed * params: any parameters needed
* portalName: name of portal being used
* dest: where to send results * dest: where to send results
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
* in which to store a command completion status string. * in which to store a command completion status string.
...@@ -103,7 +99,6 @@ void ...@@ -103,7 +99,6 @@ void
ProcessQuery(Query *parsetree, ProcessQuery(Query *parsetree,
Plan *plan, Plan *plan,
ParamListInfo params, ParamListInfo params,
const char *portalName,
DestReceiver *dest, DestReceiver *dest,
char *completionTag) char *completionTag)
{ {
...@@ -131,8 +126,7 @@ ProcessQuery(Query *parsetree, ...@@ -131,8 +126,7 @@ ProcessQuery(Query *parsetree,
/* /*
* Create the QueryDesc object * Create the QueryDesc object
*/ */
queryDesc = CreateQueryDesc(parsetree, plan, dest, portalName, params, queryDesc = CreateQueryDesc(parsetree, plan, dest, params, false);
false);
/* /*
* Call ExecStart to prepare the plan for execution * Call ExecStart to prepare the plan for execution
...@@ -269,7 +263,6 @@ PortalStart(Portal portal, ParamListInfo params) ...@@ -269,7 +263,6 @@ PortalStart(Portal portal, ParamListInfo params)
queryDesc = CreateQueryDesc((Query *) lfirst(portal->parseTrees), queryDesc = CreateQueryDesc((Query *) lfirst(portal->parseTrees),
(Plan *) lfirst(portal->planTrees), (Plan *) lfirst(portal->planTrees),
None_Receiver, None_Receiver,
portal->name,
params, params,
false); false);
/* /*
...@@ -281,7 +274,7 @@ PortalStart(Portal portal, ParamListInfo params) ...@@ -281,7 +274,7 @@ PortalStart(Portal portal, ParamListInfo params)
*/ */
portal->queryDesc = queryDesc; portal->queryDesc = queryDesc;
/* /*
* Remember tuple descriptor * Remember tuple descriptor (computed by ExecutorStart)
*/ */
portal->tupDesc = queryDesc->tupDesc; portal->tupDesc = queryDesc->tupDesc;
/* /*
...@@ -320,6 +313,53 @@ PortalStart(Portal portal, ParamListInfo params) ...@@ -320,6 +313,53 @@ PortalStart(Portal portal, ParamListInfo params)
portal->portalReady = true; portal->portalReady = true;
} }
/*
* 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 * PortalRun
* Run a portal's query or queries. * Run a portal's query or queries.
...@@ -399,8 +439,7 @@ PortalRun(Portal portal, long count, ...@@ -399,8 +439,7 @@ PortalRun(Portal portal, long count,
DestReceiver *treceiver; DestReceiver *treceiver;
PortalCreateHoldStore(portal); PortalCreateHoldStore(portal);
treceiver = CreateTuplestoreDestReceiver(portal->holdStore, treceiver = CreateDestReceiver(Tuplestore, portal);
portal->holdContext);
PortalRunUtility(portal, lfirst(portal->parseTrees), PortalRunUtility(portal, lfirst(portal->parseTrees),
treceiver, NULL); treceiver, NULL);
(*treceiver->destroy) (treceiver); (*treceiver->destroy) (treceiver);
...@@ -604,16 +643,9 @@ static uint32 ...@@ -604,16 +643,9 @@ static uint32
RunFromStore(Portal portal, ScanDirection direction, long count, RunFromStore(Portal portal, ScanDirection direction, long count,
DestReceiver *dest) DestReceiver *dest)
{ {
List *targetlist;
long current_tuple_count = 0; long current_tuple_count = 0;
if (portal->strategy == PORTAL_ONE_SELECT) (*dest->startup) (dest, CMD_SELECT, portal->tupDesc);
targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist;
else
targetlist = NIL;
(*dest->startup) (dest, CMD_SELECT, portal->name, portal->tupDesc,
targetlist);
if (direction == NoMovementScanDirection) if (direction == NoMovementScanDirection)
{ {
...@@ -737,11 +769,9 @@ PortalRunMulti(Portal portal, ...@@ -737,11 +769,9 @@ PortalRunMulti(Portal portal,
* but the results will be discarded unless you use "simple Query" * but the results will be discarded unless you use "simple Query"
* protocol. * protocol.
*/ */
if (dest->mydest == RemoteExecute || if (dest->mydest == RemoteExecute)
dest->mydest == RemoteExecuteInternal)
dest = None_Receiver; dest = None_Receiver;
if (altdest->mydest == RemoteExecute || if (altdest->mydest == RemoteExecute)
altdest->mydest == RemoteExecuteInternal)
altdest = None_Receiver; altdest = None_Receiver;
/* /*
...@@ -791,14 +821,14 @@ PortalRunMulti(Portal portal, ...@@ -791,14 +821,14 @@ PortalRunMulti(Portal portal,
{ {
/* statement can set tag string */ /* statement can set tag string */
ProcessQuery(query, plan, ProcessQuery(query, plan,
portal->portalParams, portal->name, portal->portalParams,
dest, completionTag); dest, completionTag);
} }
else else
{ {
/* stmt added by rewrite cannot set tag */ /* stmt added by rewrite cannot set tag */
ProcessQuery(query, plan, ProcessQuery(query, plan,
portal->portalParams, portal->name, portal->portalParams,
altdest, NULL); altdest, NULL);
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: printtup.h,v 1.26 2003/05/06 20:26:27 tgl Exp $ * $Id: printtup.h,v 1.27 2003/05/08 18:16:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,18 +16,19 @@ ...@@ -16,18 +16,19 @@
#include "tcop/dest.h" #include "tcop/dest.h"
extern DestReceiver *printtup_create_DR(CommandDest dest); extern DestReceiver *printtup_create_DR(CommandDest dest, Portal portal);
extern void SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist); extern void SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist,
int16 *formats);
extern void debugStartup(DestReceiver *self, int operation, extern void debugStartup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo, List *targetlist); TupleDesc typeinfo);
extern void debugtup(HeapTuple tuple, TupleDesc typeinfo, extern void debugtup(HeapTuple tuple, TupleDesc typeinfo,
DestReceiver *self); DestReceiver *self);
/* XXX these are really in executor/spi.c */ /* XXX these are really in executor/spi.c */
extern void spi_dest_startup(DestReceiver *self, int operation, extern void spi_dest_startup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo, List *targetlist); TupleDesc typeinfo);
extern void spi_printtup(HeapTuple tuple, TupleDesc typeinfo, extern void spi_printtup(HeapTuple tuple, TupleDesc typeinfo,
DestReceiver *self); DestReceiver *self);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: execdesc.h,v 1.23 2003/05/06 20:26:28 tgl Exp $ * $Id: execdesc.h,v 1.24 2003/05/08 18:16:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -34,7 +34,6 @@ typedef struct QueryDesc ...@@ -34,7 +34,6 @@ typedef struct QueryDesc
Query *parsetree; /* rewritten parsetree */ Query *parsetree; /* rewritten parsetree */
Plan *plantree; /* planner's output */ Plan *plantree; /* planner's output */
DestReceiver *dest; /* the destination for tuple output */ DestReceiver *dest; /* the destination for tuple output */
const char *portalName; /* name of portal, or NULL */
ParamListInfo params; /* param values being passed in */ ParamListInfo params; /* param values being passed in */
bool doInstrument; /* TRUE requests runtime instrumentation */ bool doInstrument; /* TRUE requests runtime instrumentation */
...@@ -46,7 +45,7 @@ typedef struct QueryDesc ...@@ -46,7 +45,7 @@ typedef struct QueryDesc
/* in pquery.c */ /* in pquery.c */
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree, extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
DestReceiver *dest, const char *portalName, DestReceiver *dest,
ParamListInfo params, ParamListInfo params,
bool doInstrument); bool doInstrument);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pqcomm.h,v 1.83 2003/05/06 21:51:42 tgl Exp $ * $Id: pqcomm.h,v 1.84 2003/05/08 18:16:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -106,7 +106,7 @@ typedef union SockAddr ...@@ -106,7 +106,7 @@ typedef union SockAddr
/* The earliest and latest frontend/backend protocol version supported. */ /* The earliest and latest frontend/backend protocol version supported. */
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0) #define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0)
#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,107) /* XXX temporary value */ #define PG_PROTOCOL_LATEST PG_PROTOCOL(3,108) /* XXX temporary value */
typedef uint32 ProtocolVersion; /* FE/BE protocol version number */ typedef uint32 ProtocolVersion; /* FE/BE protocol version number */
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pqformat.h,v 1.15 2003/04/22 00:08:07 tgl Exp $ * $Id: pqformat.h,v 1.16 2003/05/08 18:16:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
extern void pq_beginmessage(StringInfo buf, char msgtype); extern void pq_beginmessage(StringInfo buf, char msgtype);
extern void pq_sendbyte(StringInfo buf, int byt); extern void pq_sendbyte(StringInfo buf, int byt);
extern void pq_sendbytes(StringInfo buf, const char *data, int datalen); extern void pq_sendbytes(StringInfo buf, const char *data, int datalen);
extern void pq_sendcountedtext(StringInfo buf, const char *str, int slen); extern void pq_sendcountedtext(StringInfo buf, const char *str, int slen,
bool countincludesself);
extern void pq_sendstring(StringInfo buf, const char *str); extern void pq_sendstring(StringInfo buf, const char *str);
extern void pq_sendint(StringInfo buf, int i, int b); extern void pq_sendint(StringInfo buf, int i, int b);
extern void pq_endmessage(StringInfo buf); extern void pq_endmessage(StringInfo buf);
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: dest.h,v 1.37 2003/05/06 20:26:28 tgl Exp $ * $Id: dest.h,v 1.38 2003/05/08 18:16:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -82,12 +82,9 @@ typedef enum ...@@ -82,12 +82,9 @@ typedef enum
None, /* results are discarded */ None, /* results are discarded */
Debug, /* results go to debugging output */ Debug, /* results go to debugging output */
Remote, /* results sent to frontend process */ Remote, /* results sent to frontend process */
RemoteInternal, /* results sent to frontend process in
* internal (binary) form */
SPI, /* results sent to SPI manager */
Tuplestore, /* results sent to Tuplestore */
RemoteExecute, /* sent to frontend, in Execute command */ RemoteExecute, /* sent to frontend, in Execute command */
RemoteExecuteInternal /* same, but binary format */ SPI, /* results sent to SPI manager */
Tuplestore /* results sent to Tuplestore */
} CommandDest; } CommandDest;
/* ---------------- /* ----------------
...@@ -106,13 +103,13 @@ typedef struct _DestReceiver DestReceiver; ...@@ -106,13 +103,13 @@ typedef struct _DestReceiver DestReceiver;
struct _DestReceiver struct _DestReceiver
{ {
/* Called for each tuple to be output: */ /* Called for each tuple to be output: */
void (*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo, void (*receiveTuple) (HeapTuple tuple,
TupleDesc typeinfo,
DestReceiver *self); DestReceiver *self);
/* Per-executor-run initialization and shutdown: */ /* Per-executor-run initialization and shutdown: */
void (*startup) (DestReceiver *self, int operation, void (*startup) (DestReceiver *self,
const char *portalName, int operation,
TupleDesc typeinfo, TupleDesc typeinfo);
List *targetlist);
void (*shutdown) (DestReceiver *self); void (*shutdown) (DestReceiver *self);
/* Destroy the receiver object itself (if dynamically allocated) */ /* Destroy the receiver object itself (if dynamically allocated) */
void (*destroy) (DestReceiver *self); void (*destroy) (DestReceiver *self);
...@@ -123,10 +120,14 @@ struct _DestReceiver ...@@ -123,10 +120,14 @@ struct _DestReceiver
extern DestReceiver *None_Receiver; /* permanent receiver for None */ extern DestReceiver *None_Receiver; /* permanent receiver for None */
/* This is a forward reference to utils/portal.h */
typedef struct PortalData *Portal;
/* The primary destination management functions */ /* The primary destination management functions */
extern void BeginCommand(const char *commandTag, CommandDest dest); extern void BeginCommand(const char *commandTag, CommandDest dest);
extern DestReceiver *CreateDestReceiver(CommandDest dest); extern DestReceiver *CreateDestReceiver(CommandDest dest, Portal portal);
extern void EndCommand(const char *commandTag, CommandDest dest); extern void EndCommand(const char *commandTag, CommandDest dest);
/* Additional functions that go with destination management, more or less. */ /* Additional functions that go with destination management, more or less. */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pquery.h,v 1.26 2003/05/06 20:26:28 tgl Exp $ * $Id: pquery.h,v 1.27 2003/05/08 18:16:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
extern void ProcessQuery(Query *parsetree, extern void ProcessQuery(Query *parsetree,
Plan *plan, Plan *plan,
ParamListInfo params, ParamListInfo params,
const char *portalName,
DestReceiver *dest, DestReceiver *dest,
char *completionTag); char *completionTag);
...@@ -28,6 +27,9 @@ extern PortalStrategy ChoosePortalStrategy(List *parseTrees); ...@@ -28,6 +27,9 @@ extern PortalStrategy ChoosePortalStrategy(List *parseTrees);
extern void PortalStart(Portal portal, ParamListInfo params); extern void PortalStart(Portal portal, ParamListInfo params);
extern void PortalSetResultFormat(Portal portal, int nFormats,
int16 *formats);
extern bool PortalRun(Portal portal, long count, extern bool PortalRun(Portal portal, long count,
DestReceiver *dest, DestReceiver *altdest, DestReceiver *dest, DestReceiver *altdest,
char *completionTag); char *completionTag);
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: portal.h,v 1.43 2003/05/06 20:26:28 tgl Exp $ * $Id: portal.h,v 1.44 2003/05/08 18:16:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -79,7 +79,10 @@ typedef enum PortalStrategy ...@@ -79,7 +79,10 @@ typedef enum PortalStrategy
PORTAL_MULTI_QUERY PORTAL_MULTI_QUERY
} PortalStrategy; } PortalStrategy;
typedef struct PortalData *Portal; /*
* Note: typedef Portal is declared in tcop/dest.h as
* typedef struct PortalData *Portal;
*/
typedef struct PortalData typedef struct PortalData
{ {
...@@ -119,6 +122,8 @@ typedef struct PortalData ...@@ -119,6 +122,8 @@ typedef struct PortalData
/* If portal returns tuples, this is their tupdesc: */ /* If portal returns tuples, this is their tupdesc: */
TupleDesc tupDesc; /* descriptor for result tuples */ TupleDesc tupDesc; /* descriptor for result tuples */
/* and these are the format codes to use for the columns: */
int16 *formats; /* a format code for each column */
/* /*
* Where we store tuples for a held cursor or a PORTAL_UTIL_SELECT query. * Where we store tuples for a held cursor or a PORTAL_UTIL_SELECT query.
......
This diff is collapsed.
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: libpq-int.h,v 1.68 2003/05/06 21:51:42 tgl Exp $ * $Id: libpq-int.h,v 1.69 2003/05/08 18:16:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast ...@@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast
* pqcomm.h describe what the backend knows, not what libpq knows. * pqcomm.h describe what the backend knows, not what libpq knows.
*/ */
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,107) /* XXX temporary value */ #define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,108) /* XXX temporary value */
/* /*
* POSTGRES backend dependent Constants. * POSTGRES backend dependent Constants.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment