1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

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 ...
This commit is contained in:
Tom Lane
1999-01-27 00:36:28 +00:00
parent 36693c0525
commit 422221c90d
9 changed files with 413 additions and 231 deletions

View File

@ -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,182 +55,43 @@
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);
void (*
DestToFunction(CommandDest dest)) (HeapTuple, TupleDesc)
static void
donothingSetup (DestReceiver* self, TupleDesc typeinfo)
{
switch (dest)
{
case RemoteInternal:
return printtup_internal;
break;
}
case Remote:
return printtup;
break;
case Local:
return be_printtup;
break;
case Debug:
return debugtup;
break;
case SPI:
return spi_printtup;
break;
case None:
default:
return donothing;
break;
}
/*
* never gets here, but DECstation lint appears to be stupid...
*/
return donothing;
static void
donothingCleanup (DestReceiver* self)
{
}
/* ----------------
* EndCommand - tell destination that no more tuples will arrive
* static DestReceiver structs for dest types needing no local state
* ----------------
*/
void
EndCommand(char *commandTag, CommandDest dest)
{
char buf[64];
switch (dest)
{
case RemoteInternal:
case Remote:
/* ----------------
* tell the fe that the query is over
* ----------------
*/
pq_putnchar("C", 1);
sprintf(buf, "%s%s", commandTag, CommandInfo);
CommandInfo[0] = 0;
pq_putstr(buf);
break;
case Local:
case Debug:
case None:
default:
break;
}
}
/*
* These are necessary to sync communications between fe/be processes doing
* COPY rel TO stdout
*
* or
*
* COPY rel FROM stdin
*
* NOTE: the message code letters are changed at protocol version 2.0
* to eliminate possible confusion with data tuple messages.
*/
void
SendCopyBegin(void)
{
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
pq_putnchar("H", 1); /* new way */
else
pq_putnchar("B", 1); /* old way */
}
void
ReceiveCopyBegin(void)
{
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
pq_putnchar("G", 1); /* new way */
else
pq_putnchar("D", 1); /* old way */
/* We *must* flush here to ensure FE knows it can send. */
pq_flush();
}
/* ----------------
* NullCommand - tell dest that an empty query string was recognized
*
* In FE/BE protocol version 1.0, this hack is necessary to support
* libpq's crufty way of determining whether a multiple-command
* query string is done. In protocol 2.0 it's probably not really
* necessary to distinguish empty queries anymore, but we still do it
* for backwards compatibility with 1.0.
* ----------------
*/
void
NullCommand(CommandDest dest)
{
switch (dest)
{
case RemoteInternal:
case Remote:
{
/* ----------------
* tell the fe that we saw an empty query string
* ----------------
*/
pq_putstr("I");
}
break;
case Local:
case Debug:
case None:
default:
break;
}
}
/* ----------------
* ReadyForQuery - tell dest that we are ready for a new query
*
* The ReadyForQuery message is sent in protocol versions 2.0 and up
* so that the FE can tell when we are done processing a query string.
*
* Note that by flushing the stdio buffer here, we can avoid doing it
* most other places and thus reduce the number of separate packets sent.
* ----------------
*/
void
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;
}
}
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
@ -245,16 +114,16 @@ BeginCommand(char *pname,
switch (dest)
{
case RemoteInternal:
case Remote:
case RemoteInternal:
/* ----------------
* if this is a "retrieve portal" query, just return
* if this is a "retrieve portal" query, done
* because nothing needs to be sent to the fe.
* ----------------
*/
CommandInfo[0] = 0;
CommandInfo[0] = '\0';
if (isIntoPortal)
return;
break;
/* ----------------
* if portal name not specified for remote query,
@ -336,12 +205,179 @@ BeginCommand(char *pname,
}
}
/* ----------------
* DestToFunction - return appropriate receiver function set for dest
* ----------------
*/
DestReceiver*
DestToFunction(CommandDest dest)
{
switch (dest)
{
case Remote:
/* printtup wants a dynamically allocated DestReceiver */
return printtup_create_DR();
break;
case RemoteInternal:
return & printtup_internalDR;
break;
case Local:
return & be_printtupDR;
break;
case Debug:
return & debugtupDR;
break;
case SPI:
return & spi_printtupDR;
break;
case None:
default:
return & donothingDR;
break;
}
/*
* never gets here, but DECstation lint appears to be stupid...
*/
return & donothingDR;
}
/* ----------------
* EndCommand - tell destination that no more tuples will arrive
* ----------------
*/
void
EndCommand(char *commandTag, CommandDest dest)
{
char buf[64];
switch (dest)
{
case Remote:
case RemoteInternal:
/* ----------------
* tell the fe that the query is over
* ----------------
*/
sprintf(buf, "C%s%s", commandTag, CommandInfo);
pq_putstr(buf);
CommandInfo[0] = '\0';
break;
case Local:
case Debug:
case None:
default:
break;
}
}
/*
* These are necessary to sync communications between fe/be processes doing
* COPY rel TO stdout
*
* or
*
* COPY rel FROM stdin
*
* NOTE: the message code letters are changed at protocol version 2.0
* to eliminate possible confusion with data tuple messages.
*/
void
SendCopyBegin(void)
{
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
pq_putnchar("H", 1); /* new way */
else
pq_putnchar("B", 1); /* old way */
}
void
ReceiveCopyBegin(void)
{
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
pq_putnchar("G", 1); /* new way */
else
pq_putnchar("D", 1); /* old way */
/* We *must* flush here to ensure FE knows it can send. */
pq_flush();
}
/* ----------------
* NullCommand - tell dest that an empty query string was recognized
*
* In FE/BE protocol version 1.0, this hack is necessary to support
* libpq's crufty way of determining whether a multiple-command
* query string is done. In protocol 2.0 it's probably not really
* necessary to distinguish empty queries anymore, but we still do it
* for backwards compatibility with 1.0.
* ----------------
*/
void
NullCommand(CommandDest dest)
{
switch (dest)
{
case RemoteInternal:
case Remote:
/* ----------------
* tell the fe that we saw an empty query string
* ----------------
*/
pq_putstr("I");
break;
case Local:
case Debug:
case None:
default:
break;
}
}
/* ----------------
* ReadyForQuery - tell dest that we are ready for a new query
*
* The ReadyForQuery message is sent in protocol versions 2.0 and up
* so that the FE can tell when we are done processing a query string.
*
* Note that by flushing the stdio buffer here, we can avoid doing it
* most other places and thus reduce the number of separate packets sent.
* ----------------
*/
void
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;
}
}
void
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;
}