diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 1999-01-27 00:36:28 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 1999-01-27 00:36:28 +0000 |
commit | 422221c90de5d65213e8e697ac0da77098ba22a9 (patch) | |
tree | 2248f8bc5a5afcf67abb052be918a32d17360dad /src | |
parent | 36693c05257c7a34be8f1dd1e6b4a7ce45980fa5 (diff) | |
download | postgresql-422221c90de5d65213e8e697ac0da77098ba22a9.tar.gz postgresql-422221c90de5d65213e8e697ac0da77098ba22a9.zip |
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 ...
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/common/printtup.c | 120 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 40 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 6 | ||||
-rw-r--r-- | src/backend/libpq/be-dumpdata.c | 4 | ||||
-rw-r--r-- | src/backend/nodes/print.c | 4 | ||||
-rw-r--r-- | src/backend/tcop/dest.c | 334 | ||||
-rw-r--r-- | src/include/access/printtup.h | 20 | ||||
-rw-r--r-- | src/include/libpq/libpq.h | 8 | ||||
-rw-r--r-- | src/include/tcop/dest.h | 62 |
9 files changed, 390 insertions, 208 deletions
diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index fdf4ca86212..91273e4933f 100644 --- a/src/backend/access/common/printtup.c +++ b/src/backend/access/common/printtup.c @@ -8,7 +8,7 @@ * * * 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 @@ #include <mb/pg_wchar.h> #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 * ---------------------------------------------------------------- @@ -65,12 +69,88 @@ getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem) } /* ---------------- + * 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 * ---------------- */ -void -printtup(HeapTuple tuple, TupleDesc typeinfo) +static void +printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self) { + DR_printtup *myState = (DR_printtup*) self; int i, j, k, @@ -78,12 +158,15 @@ printtup(HeapTuple tuple, TupleDesc typeinfo) char *outputstr; Datum attr; bool isnull; - Oid typoutput, - typelem; #ifdef MULTIBYTE unsigned char *p; #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) * ---------------- @@ -120,10 +203,11 @@ printtup(HeapTuple tuple, TupleDesc typeinfo) attr = heap_getattr(tuple, i + 1, typeinfo, &isnull); if (isnull) continue; - if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid, - &typoutput, &typelem)) + if (OidIsValid(myState->myinfo[i].typoutput)) { - outputstr = fmgr(typoutput, attr, typelem, + outputstr = fmgr(myState->myinfo[i].typoutput, + attr, + myState->myinfo[i].typelem, typeinfo->attrs[i]->atttypmod); #ifdef MULTIBYTE p = pg_server_to_client(outputstr, strlen(outputstr)); @@ -148,6 +232,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 * ---------------- */ @@ -190,7 +287,7 @@ showatts(char *name, TupleDesc tupleDesc) * ---------------- */ void -debugtup(HeapTuple tuple, TupleDesc typeinfo) +debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self) { int i; Datum attr; @@ -221,11 +318,12 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo) * We use a different data prefix, e.g. 'B' instead of 'D' to * 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 -printtup_internal(HeapTuple tuple, TupleDesc typeinfo) +printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self) { int i, j, diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index e79816389cc..79cffc49f8f 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * 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); static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan, Query *parseTree, CmdType operation, int numberTuples, ScanDirection direction, - void (*printfunc) ()); -static void ExecRetrieve(TupleTableSlot *slot, void (*printfunc) (), - EState *estate); + DestReceiver *destfunc); +static void ExecRetrieve(TupleTableSlot *slot, + DestReceiver *destfunc, + EState *estate); static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid, EState *estate); static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid, @@ -171,7 +172,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) Plan *plan; TupleTableSlot *result; CommandDest dest; - void (*destination) (); + DestReceiver *destfunc; /****************** * sanity checks @@ -188,10 +189,19 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) parseTree = queryDesc->parsetree; plan = queryDesc->plantree; dest = queryDesc->dest; - destination = (void (*) ()) DestToFunction(dest); + destfunc = DestToFunction(dest); estate->es_processed = 0; 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) { @@ -202,7 +212,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) operation, ALL_TUPLES, ForwardScanDirection, - destination); + destfunc); break; case EXEC_FOR: result = ExecutePlan(estate, @@ -211,7 +221,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) operation, count, ForwardScanDirection, - destination); + destfunc); break; /****************** @@ -225,7 +235,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) operation, count, BackwardScanDirection, - destination); + destfunc); break; /****************** @@ -240,7 +250,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) operation, ONE_TUPLE, ForwardScanDirection, - destination); + destfunc); break; default: result = NULL; @@ -248,6 +258,8 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) break; } + (*destfunc->cleanup) (destfunc); + return result; } @@ -745,7 +757,7 @@ ExecutePlan(EState *estate, CmdType operation, int numberTuples, ScanDirection direction, - void (*printfunc) ()) + DestReceiver* destfunc) { JunkFilter *junkfilter; @@ -905,7 +917,7 @@ ExecutePlan(EState *estate, { case CMD_SELECT: ExecRetrieve(slot, /* slot containing tuple */ - printfunc, /* print function */ + destfunc, /* destination's tuple-receiver obj */ estate); /* */ result = slot; break; @@ -961,7 +973,7 @@ ExecutePlan(EState *estate, */ static void ExecRetrieve(TupleTableSlot *slot, - void (*printfunc) (), + DestReceiver *destfunc, EState *estate) { HeapTuple tuple; @@ -988,7 +1000,7 @@ ExecRetrieve(TupleTableSlot *slot, * send the tuple to the front end (or the screen) ****************** */ - (*printfunc) (tuple, attrtype); + (*destfunc->receiveTuple) (tuple, attrtype, destfunc); IncrRetrieved(); (estate->es_processed)++; } diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 5620cf78916..a7358425b47 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -3,7 +3,7 @@ * spi.c-- * 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; SPITupleTable *SPI_tuptable; int SPI_result; -void spi_printtup(HeapTuple tuple, TupleDesc tupdesc); - typedef struct { QueryTreeList *qtlist; @@ -566,7 +564,7 @@ SPI_pfree(void *pointer) * */ void -spi_printtup(HeapTuple tuple, TupleDesc tupdesc) +spi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver* self) { SPITupleTable *tuptable; MemoryContext oldcxt; diff --git a/src/backend/libpq/be-dumpdata.c b/src/backend/libpq/be-dumpdata.c index 70d01e4dcf8..4247b1c674c 100644 --- a/src/backend/libpq/be-dumpdata.c +++ b/src/backend/libpq/be-dumpdata.c @@ -6,7 +6,7 @@ * * 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, * ---------------- */ void -be_printtup(HeapTuple tuple, TupleDesc typeinfo) +be_printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self) { int i; Datum attr; diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c index af3a3eb8472..3acf895e7c3 100644 --- a/src/backend/nodes/print.c +++ b/src/backend/nodes/print.c @@ -7,7 +7,7 @@ * * * 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 * AUTHOR DATE MAJOR EVENT @@ -275,7 +275,7 @@ print_slot(TupleTableSlot *slot) return; } - debugtup(slot->val, slot->ttc_tupleDescriptor); + debugtup(slot->val, slot->ttc_tupleDescriptor, NULL); } static char * diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c index 0c1a7c530fd..0d946287f37 100644 --- a/src/backend/tcop/dest.c +++ b/src/backend/tcop/dest.c @@ -1,19 +1,20 @@ /*------------------------------------------------------------------------- * * 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 * * * 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 * BeginCommand - prepare destination for tuples of the given type + * DestToFunction - identify per-tuple processing routines * EndCommand - tell destination that no more tuples will arrive * NullCommand - tell dest that an empty query string was recognized * ReadyForQuery - tell dest that we are ready for a new query @@ -23,6 +24,13 @@ * tuples are returned by a query to keep the backend and the * "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 <string.h> @@ -47,44 +55,189 @@ static char CommandInfo[32] = {0}; /* ---------------- - * output functions + * dummy DestReceiver functions * ---------------- */ 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 (* - DestToFunction(CommandDest dest)) (HeapTuple, TupleDesc) +static void +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) { - case RemoteInternal: - return printtup_internal; + case Remote: + 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; + 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: - return printtup; + /* printtup wants a dynamically allocated DestReceiver */ + return printtup_create_DR(); + break; + + case RemoteInternal: + return & printtup_internalDR; break; case Local: - return be_printtup; + return & be_printtupDR; break; case Debug: - return debugtup; + return & debugtupDR; break; case SPI: - return spi_printtup; + return & spi_printtupDR; break; case None: default: - return donothing; + return & donothingDR; break; } @@ -92,7 +245,7 @@ void (* * never gets here, but DECstation lint appears to be stupid... */ - return donothing; + return & donothingDR; } /* ---------------- @@ -106,16 +259,15 @@ EndCommand(char *commandTag, CommandDest dest) switch (dest) { - case RemoteInternal: case Remote: + case RemoteInternal: /* ---------------- * tell the fe that the query is over * ---------------- */ - pq_putnchar("C", 1); - sprintf(buf, "%s%s", commandTag, CommandInfo); - CommandInfo[0] = 0; + sprintf(buf, "C%s%s", commandTag, CommandInfo); pq_putstr(buf); + CommandInfo[0] = '\0'; break; case Local: @@ -172,15 +324,13 @@ NullCommand(CommandDest dest) { switch (dest) { - case RemoteInternal: - case Remote: - { - /* ---------------- - * tell the fe that we saw an empty query string - * ---------------- - */ - pq_putstr("I"); - } + case RemoteInternal: + case Remote: + /* ---------------- + * tell the fe that we saw an empty query string + * ---------------- + */ + pq_putstr("I"); break; case Local: @@ -206,130 +356,16 @@ 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) - { case RemoteInternal: case Remote: - /* ---------------- - * if this is a "retrieve portal" query, just return - * because nothing needs to be sent to the fe. - * ---------------- - */ - 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)); - } - } + if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2) + pq_putnchar("Z", 1); + /* Flush output at end of cycle in any case. */ + pq_flush(); 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; @@ -341,7 +377,7 @@ UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples) { switch (operation) { - case CMD_INSERT: + case CMD_INSERT: if (tuples > 1) lastoid = InvalidOid; sprintf(CommandInfo, " %u %u", lastoid, tuples); @@ -351,7 +387,7 @@ UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples) sprintf(CommandInfo, " %u", tuples); break; default: - CommandInfo[0] = 0; + CommandInfo[0] = '\0'; + break; } - return; } diff --git a/src/include/access/printtup.h b/src/include/access/printtup.h index 0b4f7b0f042..c1b1c51ef89 100644 --- a/src/include/access/printtup.h +++ b/src/include/access/printtup.h @@ -6,20 +6,26 @@ * * 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 #define PRINTTUP_H -#include <access/htup.h> -#include <access/tupdesc.h> +#include <tcop/dest.h> -extern int getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem); -extern void printtup(HeapTuple tuple, TupleDesc typeinfo); +extern DestReceiver* printtup_create_DR(void); extern void showatts(char *name, TupleDesc attinfo); -extern void debugtup(HeapTuple tuple, TupleDesc typeinfo); -extern void printtup_internal(HeapTuple tuple, TupleDesc typeinfo); +extern void debugtup(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 */ diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h index cd036ca67f5..e654899909c 100644 --- a/src/include/libpq/libpq.h +++ b/src/include/libpq/libpq.h @@ -6,7 +6,7 @@ * * 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 @@ #include <netinet/in.h> #include "libpq/libpq-be.h" -#include "access/htup.h" -#include "access/tupdesc.h" +#include "tcop/dest.h" /* ---------------- @@ -236,7 +235,8 @@ extern PortalEntry *be_currentportal(void); extern PortalEntry *be_newportal(void); extern void be_typeinit(PortalEntry *entry, TupleDesc attrs, int natts); -extern void be_printtup(HeapTuple tuple, TupleDesc typeinfo); +extern void be_printtup(HeapTuple tuple, TupleDesc typeinfo, + DestReceiver* self); /* in be-pqexec.c */ diff --git a/src/include/tcop/dest.h b/src/include/tcop/dest.h index 9a0322e7260..0b5a80908be 100644 --- a/src/include/tcop/dest.h +++ b/src/include/tcop/dest.h @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * 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, * to a local portal buffer or to a remote portal buffer. * @@ -23,21 +23,40 @@ * a query internally. This is not used now but it may be * 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 * - * $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 #define DEST_H +#include <access/htup.h> #include <access/tupdesc.h> /* ---------------- - * CommandDest is used to allow the results of calling - * pg_eval() to go to the right place. + * CommandDest is a simplistic means of identifying the desired + * destination. Someday this will probably need to be improved. * ---------------- */ typedef enum @@ -51,25 +70,38 @@ typedef enum SPI /* results sent to SPI manager */ } 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 - the number of attributes +struct _DestReceiver { + /* 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 { - int numAttr; - Form_pg_attribute *attrs; -} AttrInfo; -*/ +/* The primary destination management functions */ -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); + +/* Additional functions that go with destination management, more or less. */ + extern void SendCopyBegin(void); extern void ReceiveCopyBegin(void); extern void NullCommand(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); #endif /* DEST_H */ |