Commit 422221c9 authored by Tom Lane's avatar Tom Lane

Another SELECT speedup: extract OIDs of column print functions

only once per SELECT, not once per tuple.  10% here, 10% there,
pretty soon you're talking about real speedups ...
parent 36693c05
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.39 1999/01/24 22:50:58 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.40 1999/01/27 00:36:22 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,6 +27,10 @@ ...@@ -27,6 +27,10 @@
#include <mb/pg_wchar.h> #include <mb/pg_wchar.h>
#endif #endif
static void printtup_setup(DestReceiver* self, TupleDesc typeinfo);
static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self);
static void printtup_cleanup(DestReceiver* self);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* printtup / debugtup support * printtup / debugtup support
* ---------------------------------------------------------------- * ----------------------------------------------------------------
...@@ -64,13 +68,89 @@ getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem) ...@@ -64,13 +68,89 @@ getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem)
return 0; return 0;
} }
/* ----------------
* Private state for a printtup destination object
* ----------------
*/
typedef struct { /* Per-attribute information */
Oid typoutput; /* Oid for the attribute's type output fn */
Oid typelem; /* typelem value to pass to the output fn */
/* more soon... */
} PrinttupAttrInfo;
typedef struct {
DestReceiver pub; /* publicly-known function pointers */
TupleDesc attrinfo; /* The attr info we are set up for */
int nattrs;
PrinttupAttrInfo *myinfo; /* Cached info about each attr */
} DR_printtup;
/* ----------------
* Initialize: create a DestReceiver for printtup
* ----------------
*/
DestReceiver*
printtup_create_DR()
{
DR_printtup* self = (DR_printtup*) palloc(sizeof(DR_printtup));
self->pub.receiveTuple = printtup;
self->pub.setup = printtup_setup;
self->pub.cleanup = printtup_cleanup;
self->attrinfo = NULL;
self->nattrs = 0;
self->myinfo = NULL;
return (DestReceiver*) self;
}
static void
printtup_setup(DestReceiver* self, TupleDesc typeinfo)
{
/* ----------------
* We could set up the derived attr info at this time, but we postpone it
* until the first call of printtup, for 3 reasons:
* 1. We don't waste time (compared to the old way) if there are no
* tuples at all to output.
* 2. Checking in printtup allows us to handle the case that the tuples
* change type midway through (although this probably can't happen in
* the current executor).
* 3. Right now, ExecutorRun passes a NULL for typeinfo anyway :-(
* ----------------
*/
}
static void
printtup_prepare_info(DR_printtup* myState, TupleDesc typeinfo, int numAttrs)
{
int i;
if (myState->myinfo)
pfree(myState->myinfo); /* get rid of any old data */
myState->myinfo = NULL;
myState->attrinfo = typeinfo;
myState->nattrs = numAttrs;
if (numAttrs <= 0)
return;
myState->myinfo = (PrinttupAttrInfo*)
palloc(numAttrs * sizeof(PrinttupAttrInfo));
for (i = 0; i < numAttrs; i++)
{
PrinttupAttrInfo* thisState = myState->myinfo + i;
getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
&thisState->typoutput, &thisState->typelem);
}
}
/* ---------------- /* ----------------
* printtup * printtup
* ---------------- * ----------------
*/ */
void static void
printtup(HeapTuple tuple, TupleDesc typeinfo) printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
{ {
DR_printtup *myState = (DR_printtup*) self;
int i, int i,
j, j,
k, k,
...@@ -78,12 +158,15 @@ printtup(HeapTuple tuple, TupleDesc typeinfo) ...@@ -78,12 +158,15 @@ printtup(HeapTuple tuple, TupleDesc typeinfo)
char *outputstr; char *outputstr;
Datum attr; Datum attr;
bool isnull; bool isnull;
Oid typoutput,
typelem;
#ifdef MULTIBYTE #ifdef MULTIBYTE
unsigned char *p; unsigned char *p;
#endif #endif
/* Set or update my derived attribute info, if needed */
if (myState->attrinfo != typeinfo ||
myState->nattrs != tuple->t_data->t_natts)
printtup_prepare_info(myState, typeinfo, tuple->t_data->t_natts);
/* ---------------- /* ----------------
* tell the frontend to expect new tuple data (in ASCII style) * tell the frontend to expect new tuple data (in ASCII style)
* ---------------- * ----------------
...@@ -120,10 +203,11 @@ printtup(HeapTuple tuple, TupleDesc typeinfo) ...@@ -120,10 +203,11 @@ printtup(HeapTuple tuple, TupleDesc typeinfo)
attr = heap_getattr(tuple, i + 1, typeinfo, &isnull); attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
if (isnull) if (isnull)
continue; continue;
if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid, if (OidIsValid(myState->myinfo[i].typoutput))
&typoutput, &typelem))
{ {
outputstr = fmgr(typoutput, attr, typelem, outputstr = fmgr(myState->myinfo[i].typoutput,
attr,
myState->myinfo[i].typelem,
typeinfo->attrs[i]->atttypmod); typeinfo->attrs[i]->atttypmod);
#ifdef MULTIBYTE #ifdef MULTIBYTE
p = pg_server_to_client(outputstr, strlen(outputstr)); p = pg_server_to_client(outputstr, strlen(outputstr));
...@@ -147,6 +231,19 @@ printtup(HeapTuple tuple, TupleDesc typeinfo) ...@@ -147,6 +231,19 @@ printtup(HeapTuple tuple, TupleDesc typeinfo)
} }
} }
/* ----------------
* printtup_cleanup
* ----------------
*/
static void
printtup_cleanup(DestReceiver* self)
{
DR_printtup* myState = (DR_printtup*) self;
if (myState->myinfo)
pfree(myState->myinfo);
pfree(myState);
}
/* ---------------- /* ----------------
* printatt * printatt
* ---------------- * ----------------
...@@ -190,7 +287,7 @@ showatts(char *name, TupleDesc tupleDesc) ...@@ -190,7 +287,7 @@ showatts(char *name, TupleDesc tupleDesc)
* ---------------- * ----------------
*/ */
void void
debugtup(HeapTuple tuple, TupleDesc typeinfo) debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
{ {
int i; int i;
Datum attr; Datum attr;
...@@ -221,11 +318,12 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo) ...@@ -221,11 +318,12 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo)
* We use a different data prefix, e.g. 'B' instead of 'D' to * We use a different data prefix, e.g. 'B' instead of 'D' to
* indicate a tuple in internal (binary) form. * indicate a tuple in internal (binary) form.
* *
* This is same as printtup, except we don't use the typout func. * This is same as printtup, except we don't use the typout func,
* and therefore have no need for persistent state.
* ---------------- * ----------------
*/ */
void void
printtup_internal(HeapTuple tuple, TupleDesc typeinfo) printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
{ {
int i, int i,
j, j,
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.63 1999/01/25 12:01:03 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.64 1999/01/27 00:36:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -66,9 +66,10 @@ static void EndPlan(Plan *plan, EState *estate); ...@@ -66,9 +66,10 @@ static void EndPlan(Plan *plan, EState *estate);
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan, static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
Query *parseTree, CmdType operation, Query *parseTree, CmdType operation,
int numberTuples, ScanDirection direction, int numberTuples, ScanDirection direction,
void (*printfunc) ()); DestReceiver *destfunc);
static void ExecRetrieve(TupleTableSlot *slot, void (*printfunc) (), static void ExecRetrieve(TupleTableSlot *slot,
EState *estate); DestReceiver *destfunc,
EState *estate);
static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid, static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
EState *estate); EState *estate);
static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid, static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
...@@ -171,7 +172,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) ...@@ -171,7 +172,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
Plan *plan; Plan *plan;
TupleTableSlot *result; TupleTableSlot *result;
CommandDest dest; CommandDest dest;
void (*destination) (); DestReceiver *destfunc;
/****************** /******************
* sanity checks * sanity checks
...@@ -188,10 +189,19 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) ...@@ -188,10 +189,19 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
parseTree = queryDesc->parsetree; parseTree = queryDesc->parsetree;
plan = queryDesc->plantree; plan = queryDesc->plantree;
dest = queryDesc->dest; dest = queryDesc->dest;
destination = (void (*) ()) DestToFunction(dest); destfunc = DestToFunction(dest);
estate->es_processed = 0; estate->es_processed = 0;
estate->es_lastoid = InvalidOid; estate->es_lastoid = InvalidOid;
/******************
* FIXME: the dest setup function ought to be handed the tuple desc
* for the tuples to be output, but I'm not quite sure how to get that
* info at this point. For now, passing NULL is OK because no existing
* dest setup function actually uses the pointer.
******************
*/
(*destfunc->setup) (destfunc, (TupleDesc) NULL);
switch (feature) switch (feature)
{ {
...@@ -202,7 +212,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) ...@@ -202,7 +212,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
operation, operation,
ALL_TUPLES, ALL_TUPLES,
ForwardScanDirection, ForwardScanDirection,
destination); destfunc);
break; break;
case EXEC_FOR: case EXEC_FOR:
result = ExecutePlan(estate, result = ExecutePlan(estate,
...@@ -211,7 +221,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) ...@@ -211,7 +221,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
operation, operation,
count, count,
ForwardScanDirection, ForwardScanDirection,
destination); destfunc);
break; break;
/****************** /******************
...@@ -225,7 +235,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) ...@@ -225,7 +235,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
operation, operation,
count, count,
BackwardScanDirection, BackwardScanDirection,
destination); destfunc);
break; break;
/****************** /******************
...@@ -240,7 +250,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) ...@@ -240,7 +250,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
operation, operation,
ONE_TUPLE, ONE_TUPLE,
ForwardScanDirection, ForwardScanDirection,
destination); destfunc);
break; break;
default: default:
result = NULL; result = NULL;
...@@ -248,6 +258,8 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) ...@@ -248,6 +258,8 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
break; break;
} }
(*destfunc->cleanup) (destfunc);
return result; return result;
} }
...@@ -745,7 +757,7 @@ ExecutePlan(EState *estate, ...@@ -745,7 +757,7 @@ ExecutePlan(EState *estate,
CmdType operation, CmdType operation,
int numberTuples, int numberTuples,
ScanDirection direction, ScanDirection direction,
void (*printfunc) ()) DestReceiver* destfunc)
{ {
JunkFilter *junkfilter; JunkFilter *junkfilter;
...@@ -905,7 +917,7 @@ ExecutePlan(EState *estate, ...@@ -905,7 +917,7 @@ ExecutePlan(EState *estate,
{ {
case CMD_SELECT: case CMD_SELECT:
ExecRetrieve(slot, /* slot containing tuple */ ExecRetrieve(slot, /* slot containing tuple */
printfunc, /* print function */ destfunc, /* destination's tuple-receiver obj */
estate); /* */ estate); /* */
result = slot; result = slot;
break; break;
...@@ -961,7 +973,7 @@ ExecutePlan(EState *estate, ...@@ -961,7 +973,7 @@ ExecutePlan(EState *estate,
*/ */
static void static void
ExecRetrieve(TupleTableSlot *slot, ExecRetrieve(TupleTableSlot *slot,
void (*printfunc) (), DestReceiver *destfunc,
EState *estate) EState *estate)
{ {
HeapTuple tuple; HeapTuple tuple;
...@@ -988,7 +1000,7 @@ ExecRetrieve(TupleTableSlot *slot, ...@@ -988,7 +1000,7 @@ ExecRetrieve(TupleTableSlot *slot,
* send the tuple to the front end (or the screen) * send the tuple to the front end (or the screen)
****************** ******************
*/ */
(*printfunc) (tuple, attrtype); (*destfunc->receiveTuple) (tuple, attrtype, destfunc);
IncrRetrieved(); IncrRetrieved();
(estate->es_processed)++; (estate->es_processed)++;
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* spi.c-- * spi.c--
* Server Programming Interface * Server Programming Interface
* *
* $Id: spi.c,v 1.30 1999/01/24 05:40:48 tgl Exp $ * $Id: spi.c,v 1.31 1999/01/27 00:36:21 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -32,8 +32,6 @@ uint32 SPI_processed = 0; ...@@ -32,8 +32,6 @@ uint32 SPI_processed = 0;
SPITupleTable *SPI_tuptable; SPITupleTable *SPI_tuptable;
int SPI_result; int SPI_result;
void spi_printtup(HeapTuple tuple, TupleDesc tupdesc);
typedef struct typedef struct
{ {
QueryTreeList *qtlist; QueryTreeList *qtlist;
...@@ -566,7 +564,7 @@ SPI_pfree(void *pointer) ...@@ -566,7 +564,7 @@ SPI_pfree(void *pointer)
* *
*/ */
void void
spi_printtup(HeapTuple tuple, TupleDesc tupdesc) spi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver* self)
{ {
SPITupleTable *tuptable; SPITupleTable *tuptable;
MemoryContext oldcxt; MemoryContext oldcxt;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: be-dumpdata.c,v 1.20 1999/01/24 05:40:49 tgl Exp $ * $Id: be-dumpdata.c,v 1.21 1999/01/27 00:36:12 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -208,7 +208,7 @@ be_typeinit(PortalEntry *entry, ...@@ -208,7 +208,7 @@ be_typeinit(PortalEntry *entry,
* ---------------- * ----------------
*/ */
void void
be_printtup(HeapTuple tuple, TupleDesc typeinfo) be_printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
{ {
int i; int i;
Datum attr; Datum attr;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.18 1998/09/01 04:29:10 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.19 1999/01/27 00:36:28 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -275,7 +275,7 @@ print_slot(TupleTableSlot *slot) ...@@ -275,7 +275,7 @@ print_slot(TupleTableSlot *slot)
return; return;
} }
debugtup(slot->val, slot->ttc_tupleDescriptor); debugtup(slot->val, slot->ttc_tupleDescriptor, NULL);
} }
static char * static char *
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* dest.c-- * dest.c--
* support for various communication destinations - see lib/H/tcop/dest.h * support for various communication destinations - see include/tcop/dest.h
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.23 1998/09/01 04:32:10 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.24 1999/01/27 00:36:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
/* /*
* INTERFACE ROUTINES * INTERFACE ROUTINES
* BeginCommand - prepare destination for tuples of the given type * BeginCommand - prepare destination for tuples of the given type
* DestToFunction - identify per-tuple processing routines
* EndCommand - tell destination that no more tuples will arrive * EndCommand - tell destination that no more tuples will arrive
* NullCommand - tell dest that an empty query string was recognized * NullCommand - tell dest that an empty query string was recognized
* ReadyForQuery - tell dest that we are ready for a new query * ReadyForQuery - tell dest that we are ready for a new query
...@@ -23,6 +24,13 @@ ...@@ -23,6 +24,13 @@
* tuples are returned by a query to keep the backend and the * tuples are returned by a query to keep the backend and the
* "destination" portals synchronized. * "destination" portals synchronized.
* *
* There is a second level of initialization/cleanup performed by the
* setup/cleanup routines identified by DestToFunction. This could
* probably be merged with the work done by BeginCommand/EndCommand,
* but as of right now BeginCommand/EndCommand are used in a rather
* unstructured way --- some places call Begin without End, some vice
* versa --- so I think I'll just leave 'em alone for now. tgl 1/99.
*
*/ */
#include <stdio.h> /* for sprintf() */ #include <stdio.h> /* for sprintf() */
#include <string.h> #include <string.h>
...@@ -47,44 +55,189 @@ ...@@ -47,44 +55,189 @@
static char CommandInfo[32] = {0}; static char CommandInfo[32] = {0};
/* ---------------- /* ----------------
* output functions * dummy DestReceiver functions
* ---------------- * ----------------
*/ */
static void static void
donothing(HeapTuple tuple, TupleDesc attrdesc) donothingReceive (HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
{ {
} }
extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc); static void
donothingSetup (DestReceiver* self, TupleDesc typeinfo)
{
}
void (* static void
DestToFunction(CommandDest dest)) (HeapTuple, TupleDesc) donothingCleanup (DestReceiver* self)
{ {
}
/* ----------------
* static DestReceiver structs for dest types needing no local state
* ----------------
*/
static DestReceiver donothingDR = {
donothingReceive, donothingSetup, donothingCleanup
};
static DestReceiver printtup_internalDR = {
printtup_internal, donothingSetup, donothingCleanup
};
static DestReceiver be_printtupDR = {
be_printtup, donothingSetup, donothingCleanup
};
static DestReceiver debugtupDR = {
debugtup, donothingSetup, donothingCleanup
};
static DestReceiver spi_printtupDR = {
spi_printtup, donothingSetup, donothingCleanup
};
/* ----------------
* BeginCommand - prepare destination for tuples of the given type
* ----------------
*/
void
BeginCommand(char *pname,
int operation,
TupleDesc tupdesc,
bool isIntoRel,
bool isIntoPortal,
char *tag,
CommandDest dest)
{
PortalEntry *entry;
Form_pg_attribute *attrs = tupdesc->attrs;
int natts = tupdesc->natts;
int i;
char *p;
switch (dest) switch (dest)
{ {
case RemoteInternal: case Remote:
return printtup_internal; case RemoteInternal:
/* ----------------
* if this is a "retrieve portal" query, done
* because nothing needs to be sent to the fe.
* ----------------
*/
CommandInfo[0] = '\0';
if (isIntoPortal)
break;
/* ----------------
* if portal name not specified for remote query,
* use the "blank" portal.
* ----------------
*/
if (pname == NULL)
pname = "blank";
/* ----------------
* send fe info on tuples we're about to send
* ----------------
*/
pq_putnchar("P", 1);/* new portal.. */
pq_putstr(pname); /* portal name */
/* ----------------
* if this is a retrieve, then we send back the tuple
* descriptor of the tuples. "retrieve into" is an
* exception because no tuples are returned in that case.
* ----------------
*/
if (operation == CMD_SELECT && !isIntoRel)
{
pq_putnchar("T", 1); /* type info to follow.. */
pq_putint(natts, 2); /* number of attributes in tuples */
for (i = 0; i < natts; ++i)
{
pq_putstr(attrs[i]->attname.data);
pq_putint((int) attrs[i]->atttypid, sizeof(attrs[i]->atttypid));
pq_putint(attrs[i]->attlen, sizeof(attrs[i]->attlen));
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
pq_putint(attrs[i]->atttypmod, sizeof(attrs[i]->atttypmod));
}
}
break; break;
case Local:
/* ----------------
* prepare local portal buffer for query results
* and setup result for PQexec()
* ----------------
*/
entry = be_currentportal();
if (pname != NULL)
pbuf_setportalinfo(entry, pname);
if (operation == CMD_SELECT && !isIntoRel)
{
be_typeinit(entry, tupdesc, natts);
p = (char *) palloc(strlen(entry->name) + 2);
p[0] = 'P';
strcpy(p + 1, entry->name);
}
else
{
p = (char *) palloc(strlen(tag) + 2);
p[0] = 'C';
strcpy(p + 1, tag);
}
entry->result = p;
break;
case Debug:
/* ----------------
* show the return type of the tuples
* ----------------
*/
if (pname == NULL)
pname = "blank";
showatts(pname, tupdesc);
break;
case None:
default:
break;
}
}
/* ----------------
* DestToFunction - return appropriate receiver function set for dest
* ----------------
*/
DestReceiver*
DestToFunction(CommandDest dest)
{
switch (dest)
{
case Remote: case Remote:
return printtup; /* printtup wants a dynamically allocated DestReceiver */
return printtup_create_DR();
break;
case RemoteInternal:
return & printtup_internalDR;
break; break;
case Local: case Local:
return be_printtup; return & be_printtupDR;
break; break;
case Debug: case Debug:
return debugtup; return & debugtupDR;
break; break;
case SPI: case SPI:
return spi_printtup; return & spi_printtupDR;
break; break;
case None: case None:
default: default:
return donothing; return & donothingDR;
break; break;
} }
...@@ -92,7 +245,7 @@ void (* ...@@ -92,7 +245,7 @@ void (*
* never gets here, but DECstation lint appears to be stupid... * never gets here, but DECstation lint appears to be stupid...
*/ */
return donothing; return & donothingDR;
} }
/* ---------------- /* ----------------
...@@ -106,16 +259,15 @@ EndCommand(char *commandTag, CommandDest dest) ...@@ -106,16 +259,15 @@ EndCommand(char *commandTag, CommandDest dest)
switch (dest) switch (dest)
{ {
case RemoteInternal:
case Remote: case Remote:
case RemoteInternal:
/* ---------------- /* ----------------
* tell the fe that the query is over * tell the fe that the query is over
* ---------------- * ----------------
*/ */
pq_putnchar("C", 1); sprintf(buf, "C%s%s", commandTag, CommandInfo);
sprintf(buf, "%s%s", commandTag, CommandInfo);
CommandInfo[0] = 0;
pq_putstr(buf); pq_putstr(buf);
CommandInfo[0] = '\0';
break; break;
case Local: case Local:
...@@ -172,15 +324,13 @@ NullCommand(CommandDest dest) ...@@ -172,15 +324,13 @@ NullCommand(CommandDest dest)
{ {
switch (dest) switch (dest)
{ {
case RemoteInternal: case RemoteInternal:
case Remote: case Remote:
{ /* ----------------
/* ---------------- * tell the fe that we saw an empty query string
* tell the fe that we saw an empty query string * ----------------
* ---------------- */
*/ pq_putstr("I");
pq_putstr("I");
}
break; break;
case Local: case Local:
...@@ -204,132 +354,18 @@ NullCommand(CommandDest dest) ...@@ -204,132 +354,18 @@ NullCommand(CommandDest dest)
void void
ReadyForQuery(CommandDest dest) ReadyForQuery(CommandDest dest)
{ {
switch (dest)
{
case RemoteInternal:
case Remote:
{
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
pq_putnchar("Z", 1);
/* Flush output at end of cycle in any case. */
pq_flush();
}
break;
case Local:
case Debug:
case None:
default:
break;
}
}
/* ----------------
* BeginCommand - prepare destination for tuples of the given type
* ----------------
*/
void
BeginCommand(char *pname,
int operation,
TupleDesc tupdesc,
bool isIntoRel,
bool isIntoPortal,
char *tag,
CommandDest dest)
{
PortalEntry *entry;
Form_pg_attribute *attrs = tupdesc->attrs;
int natts = tupdesc->natts;
int i;
char *p;
switch (dest) switch (dest)
{ {
case RemoteInternal: case RemoteInternal:
case Remote: case Remote:
/* ---------------- if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
* if this is a "retrieve portal" query, just return pq_putnchar("Z", 1);
* because nothing needs to be sent to the fe. /* Flush output at end of cycle in any case. */
* ---------------- pq_flush();
*/
CommandInfo[0] = 0;
if (isIntoPortal)
return;
/* ----------------
* if portal name not specified for remote query,
* use the "blank" portal.
* ----------------
*/
if (pname == NULL)
pname = "blank";
/* ----------------
* send fe info on tuples we're about to send
* ----------------
*/
pq_putnchar("P", 1);/* new portal.. */
pq_putstr(pname); /* portal name */
/* ----------------
* if this is a retrieve, then we send back the tuple
* descriptor of the tuples. "retrieve into" is an
* exception because no tuples are returned in that case.
* ----------------
*/
if (operation == CMD_SELECT && !isIntoRel)
{
pq_putnchar("T", 1); /* type info to follow.. */
pq_putint(natts, 2); /* number of attributes in tuples */
for (i = 0; i < natts; ++i)
{
pq_putstr(attrs[i]->attname.data);
pq_putint((int) attrs[i]->atttypid, sizeof(attrs[i]->atttypid));
pq_putint(attrs[i]->attlen, sizeof(attrs[i]->attlen));
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
pq_putint(attrs[i]->atttypmod, sizeof(attrs[i]->atttypmod));
}
}
break; break;
case Local: case Local:
/* ----------------
* prepare local portal buffer for query results
* and setup result for PQexec()
* ----------------
*/
entry = be_currentportal();
if (pname != NULL)
pbuf_setportalinfo(entry, pname);
if (operation == CMD_SELECT && !isIntoRel)
{
be_typeinit(entry, tupdesc, natts);
p = (char *) palloc(strlen(entry->name) + 2);
p[0] = 'P';
strcpy(p + 1, entry->name);
}
else
{
p = (char *) palloc(strlen(tag) + 2);
p[0] = 'C';
strcpy(p + 1, tag);
}
entry->result = p;
break;
case Debug: case Debug:
/* ----------------
* show the return type of the tuples
* ----------------
*/
if (pname == NULL)
pname = "blank";
showatts(pname, tupdesc);
break;
case None: case None:
default: default:
break; break;
...@@ -341,7 +377,7 @@ UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples) ...@@ -341,7 +377,7 @@ UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples)
{ {
switch (operation) switch (operation)
{ {
case CMD_INSERT: case CMD_INSERT:
if (tuples > 1) if (tuples > 1)
lastoid = InvalidOid; lastoid = InvalidOid;
sprintf(CommandInfo, " %u %u", lastoid, tuples); sprintf(CommandInfo, " %u %u", lastoid, tuples);
...@@ -351,7 +387,7 @@ UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples) ...@@ -351,7 +387,7 @@ UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples)
sprintf(CommandInfo, " %u", tuples); sprintf(CommandInfo, " %u", tuples);
break; break;
default: default:
CommandInfo[0] = 0; CommandInfo[0] = '\0';
break;
} }
return;
} }
...@@ -6,20 +6,26 @@ ...@@ -6,20 +6,26 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: printtup.h,v 1.6 1999/01/24 05:40:46 tgl Exp $ * $Id: printtup.h,v 1.7 1999/01/27 00:36:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef PRINTTUP_H #ifndef PRINTTUP_H
#define PRINTTUP_H #define PRINTTUP_H
#include <access/htup.h> #include <tcop/dest.h>
#include <access/tupdesc.h>
extern int getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem); extern DestReceiver* printtup_create_DR(void);
extern void printtup(HeapTuple tuple, TupleDesc typeinfo);
extern void showatts(char *name, TupleDesc attinfo); extern void showatts(char *name, TupleDesc attinfo);
extern void debugtup(HeapTuple tuple, TupleDesc typeinfo); extern void debugtup(HeapTuple tuple, TupleDesc typeinfo,
extern void printtup_internal(HeapTuple tuple, TupleDesc typeinfo); DestReceiver* self);
extern void printtup_internal(HeapTuple tuple, TupleDesc typeinfo,
DestReceiver* self);
/* XXX this one is really in executor/spi.c */
extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc,
DestReceiver* self);
extern int getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem);
#endif /* PRINTTUP_H */ #endif /* PRINTTUP_H */
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: libpq.h,v 1.25 1999/01/24 02:47:15 tgl Exp $ * $Id: libpq.h,v 1.26 1999/01/27 00:36:09 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,8 +18,7 @@ ...@@ -18,8 +18,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include "libpq/libpq-be.h" #include "libpq/libpq-be.h"
#include "access/htup.h" #include "tcop/dest.h"
#include "access/tupdesc.h"
/* ---------------- /* ----------------
...@@ -236,7 +235,8 @@ extern PortalEntry *be_currentportal(void); ...@@ -236,7 +235,8 @@ extern PortalEntry *be_currentportal(void);
extern PortalEntry *be_newportal(void); extern PortalEntry *be_newportal(void);
extern void be_typeinit(PortalEntry *entry, TupleDesc attrs, extern void be_typeinit(PortalEntry *entry, TupleDesc attrs,
int natts); int natts);
extern void be_printtup(HeapTuple tuple, TupleDesc typeinfo); extern void be_printtup(HeapTuple tuple, TupleDesc typeinfo,
DestReceiver* self);
/* in be-pqexec.c */ /* in be-pqexec.c */
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* dest.h-- * dest.h--
* Whenever the backend is submitted a query, the results * Whenever the backend executes a query, the results
* have to go someplace - either to the standard output, * have to go someplace - either to the standard output,
* to a local portal buffer or to a remote portal buffer. * to a local portal buffer or to a remote portal buffer.
* *
...@@ -23,21 +23,40 @@ ...@@ -23,21 +23,40 @@
* a query internally. This is not used now but it may be * a query internally. This is not used now but it may be
* useful for the parallel optimiser/executor. * useful for the parallel optimiser/executor.
* *
* dest.c defines three functions that implement destination management:
*
* BeginCommand: initialize the destination.
* DestToFunction: return a pointer to a struct of destination-specific
* receiver functions.
* EndCommand: clean up the destination when output is complete.
*
* The DestReceiver object returned by DestToFunction may be a statically
* allocated object (for destination types that require no local state)
* or can be a palloc'd object that has DestReceiver as its first field
* and contains additional fields (see printtup.c for an example). These
* additional fields are then accessible to the DestReceiver functions
* by casting the DestReceiver* pointer passed to them.
* The palloc'd object is pfree'd by the DestReceiver's cleanup function.
*
* XXX FIXME: the initialization and cleanup code that currently appears
* in-line in BeginCommand and EndCommand probably should be moved out
* to routines associated with each destination receiver type.
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: dest.h,v 1.16 1998/09/01 04:38:39 momjian Exp $ * $Id: dest.h,v 1.17 1999/01/27 00:36:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef DEST_H #ifndef DEST_H
#define DEST_H #define DEST_H
#include <access/htup.h>
#include <access/tupdesc.h> #include <access/tupdesc.h>
/* ---------------- /* ----------------
* CommandDest is used to allow the results of calling * CommandDest is a simplistic means of identifying the desired
* pg_eval() to go to the right place. * destination. Someday this will probably need to be improved.
* ---------------- * ----------------
*/ */
typedef enum typedef enum
...@@ -51,25 +70,38 @@ typedef enum ...@@ -51,25 +70,38 @@ typedef enum
SPI /* results sent to SPI manager */ SPI /* results sent to SPI manager */
} CommandDest; } CommandDest;
/* ----------------
* DestReceiver is a base type for destination-specific local state.
* In the simplest cases, there is no state info, just the function
* pointers that the executor must call.
* ----------------
*/
typedef struct _DestReceiver DestReceiver;
/* AttrInfo* replaced with TupleDesc, now that TupleDesc also has within it struct _DestReceiver {
the number of attributes /* Called for each tuple to be output: */
void (*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo,
DestReceiver* self);
/* Initialization and teardown: */
void (*setup) (DestReceiver* self, TupleDesc typeinfo);
void (*cleanup) (DestReceiver* self);
/* Private fields might appear beyond this point... */
};
typedef struct AttrInfo { /* The primary destination management functions */
int numAttr;
Form_pg_attribute *attrs;
} AttrInfo;
*/
extern void (*DestToFunction(CommandDest dest)) (); extern void BeginCommand(char *pname, int operation, TupleDesc attinfo,
bool isIntoRel, bool isIntoPortal, char *tag,
CommandDest dest);
extern DestReceiver* DestToFunction(CommandDest dest);
extern void EndCommand(char *commandTag, CommandDest dest); extern void EndCommand(char *commandTag, CommandDest dest);
/* Additional functions that go with destination management, more or less. */
extern void SendCopyBegin(void); extern void SendCopyBegin(void);
extern void ReceiveCopyBegin(void); extern void ReceiveCopyBegin(void);
extern void NullCommand(CommandDest dest); extern void NullCommand(CommandDest dest);
extern void ReadyForQuery(CommandDest dest); extern void ReadyForQuery(CommandDest dest);
extern void BeginCommand(char *pname, int operation, TupleDesc attinfo,
bool isIntoRel, bool isIntoPortal, char *tag,
CommandDest dest);
extern void UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples); extern void UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples);
#endif /* DEST_H */ #endif /* DEST_H */
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