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:
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user