mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
Clean up BeginCommand and related routines. BeginCommand and EndCommand
are now both invoked once per received SQL command (raw parsetree) from pg_exec_query_string. BeginCommand is actually just an empty routine at the moment --- all its former operations have been pushed into tuple receiver setup routines in printtup.c. This makes for a clean distinction between BeginCommand/EndCommand (once per command) and the tuple receiver setup/teardown routines (once per ExecutorRun call), whereas the old code was quite ad hoc. Along the way, clean up the calling conventions for ExecutorRun a little bit.
This commit is contained in:
parent
e22c9c4475
commit
6779c55c22
@ -1,15 +1,15 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* printtup.c
|
* printtup.c
|
||||||
* Routines to print out tuples to the destination (binary or non-binary
|
* Routines to print out tuples to the destination (both frontend
|
||||||
* portals, frontend/interactive backend, etc.).
|
* clients and interactive backends are supported here).
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* 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/access/common/printtup.c,v 1.60 2001/10/25 05:49:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.61 2002/02/27 19:34:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -18,10 +18,12 @@
|
|||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "access/printtup.h"
|
#include "access/printtup.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
#include "libpq/libpq.h"
|
||||||
#include "libpq/pqformat.h"
|
#include "libpq/pqformat.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
static void printtup_setup(DestReceiver *self, TupleDesc typeinfo);
|
static void printtup_setup(DestReceiver *self, int operation,
|
||||||
|
const char *portalName, TupleDesc typeinfo);
|
||||||
static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
|
static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
|
||||||
static void printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
|
static void printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
|
||||||
static void printtup_cleanup(DestReceiver *self);
|
static void printtup_cleanup(DestReceiver *self);
|
||||||
@ -97,17 +99,56 @@ printtup_create_DR(bool isBinary)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
printtup_setup(DestReceiver *self, TupleDesc typeinfo)
|
printtup_setup(DestReceiver *self, int operation,
|
||||||
|
const char *portalName, TupleDesc typeinfo)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Send portal name to frontend.
|
||||||
|
*
|
||||||
|
* If portal name not specified, use "blank" portal.
|
||||||
|
*/
|
||||||
|
if (portalName == NULL)
|
||||||
|
portalName = "blank";
|
||||||
|
|
||||||
|
pq_puttextmessage('P', portalName);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if this is a retrieve, then we send back the tuple
|
||||||
|
* descriptor of the tuples.
|
||||||
|
*/
|
||||||
|
if (operation == CMD_SELECT)
|
||||||
|
{
|
||||||
|
Form_pg_attribute *attrs = typeinfo->attrs;
|
||||||
|
int natts = typeinfo->natts;
|
||||||
|
int i;
|
||||||
|
StringInfoData buf;
|
||||||
|
|
||||||
|
pq_beginmessage(&buf);
|
||||||
|
pq_sendbyte(&buf, 'T'); /* tuple descriptor message type */
|
||||||
|
pq_sendint(&buf, natts, 2); /* # of attrs in tuples */
|
||||||
|
|
||||||
|
for (i = 0; i < natts; ++i)
|
||||||
|
{
|
||||||
|
pq_sendstring(&buf, NameStr(attrs[i]->attname));
|
||||||
|
pq_sendint(&buf, (int) attrs[i]->atttypid,
|
||||||
|
sizeof(attrs[i]->atttypid));
|
||||||
|
pq_sendint(&buf, attrs[i]->attlen,
|
||||||
|
sizeof(attrs[i]->attlen));
|
||||||
|
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
|
||||||
|
pq_sendint(&buf, attrs[i]->atttypmod,
|
||||||
|
sizeof(attrs[i]->atttypmod));
|
||||||
|
}
|
||||||
|
pq_endmessage(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* We could set up the derived attr info at this time, but we postpone it
|
* We could set up the derived attr info at this time, but we postpone it
|
||||||
* until the first call of printtup, for 3 reasons:
|
* until the first call of printtup, for 2 reasons:
|
||||||
* 1. We don't waste time (compared to the old way) if there are no
|
* 1. We don't waste time (compared to the old way) if there are no
|
||||||
* tuples at all to output.
|
* tuples at all to output.
|
||||||
* 2. Checking in printtup allows us to handle the case that the tuples
|
* 2. Checking in printtup allows us to handle the case that the tuples
|
||||||
* change type midway through (although this probably can't happen in
|
* change type midway through (although this probably can't happen in
|
||||||
* the current executor).
|
* the current executor).
|
||||||
* 3. Right now, ExecutorRun passes a NULL for typeinfo anyway :-(
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
@ -267,12 +308,12 @@ printatt(unsigned attributeId,
|
|||||||
* showatts
|
* showatts
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
showatts(char *name, TupleDesc tupleDesc)
|
showatts(const char *name, TupleDesc tupleDesc)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int natts = tupleDesc->natts;
|
int natts = tupleDesc->natts;
|
||||||
Form_pg_attribute *attinfo = tupleDesc->attrs;
|
Form_pg_attribute *attinfo = tupleDesc->attrs;
|
||||||
|
int i;
|
||||||
|
|
||||||
puts(name);
|
puts(name);
|
||||||
for (i = 0; i < natts; ++i)
|
for (i = 0; i < natts; ++i)
|
||||||
@ -281,7 +322,24 @@ showatts(char *name, TupleDesc tupleDesc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* debugtup
|
* debugSetup - prepare to print tuples for an interactive backend
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
debugSetup(DestReceiver *self, int operation,
|
||||||
|
const char *portalName, TupleDesc typeinfo)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* show the return type of the tuples
|
||||||
|
*/
|
||||||
|
if (portalName == NULL)
|
||||||
|
portalName = "blank";
|
||||||
|
|
||||||
|
showatts(portalName, typeinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* debugtup - print one tuple for an interactive backend
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.76 2001/10/25 05:49:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.77 2002/02/27 19:34:11 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* some of the executor utility code such as "ExecTypeFromTL" should be
|
* some of the executor utility code such as "ExecTypeFromTL" should be
|
||||||
@ -432,7 +432,7 @@ TupleDescInitEntry(TupleDesc desc,
|
|||||||
*
|
*
|
||||||
* (Why not just make the atttypid point to the OID type, instead of the
|
* (Why not just make the atttypid point to the OID type, instead of the
|
||||||
* type the query returns? Because the executor uses the atttypid to
|
* type the query returns? Because the executor uses the atttypid to
|
||||||
* tell the front end what type will be returned (in BeginCommand),
|
* tell the front end what type will be returned,
|
||||||
* and in the end the type returned will be the result of the query,
|
* and in the end the type returned will be the result of the query,
|
||||||
* not an OID.)
|
* not an OID.)
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.155 2002/02/26 22:47:04 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.156 2002/02/27 19:34:38 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The PerformAddAttribute() code, like most of the relation
|
* The PerformAddAttribute() code, like most of the relation
|
||||||
@ -113,6 +113,7 @@ PerformPortalFetch(char *name,
|
|||||||
QueryDesc *queryDesc;
|
QueryDesc *queryDesc;
|
||||||
EState *estate;
|
EState *estate;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
|
ScanDirection direction;
|
||||||
CommandId savedId;
|
CommandId savedId;
|
||||||
bool temp_desc = false;
|
bool temp_desc = false;
|
||||||
|
|
||||||
@ -145,6 +146,9 @@ PerformPortalFetch(char *name,
|
|||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||||
|
|
||||||
|
queryDesc = PortalGetQueryDesc(portal);
|
||||||
|
estate = PortalGetState(portal);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the requested destination is not the same as the query's
|
* If the requested destination is not the same as the query's
|
||||||
* original destination, make a temporary QueryDesc with the proper
|
* original destination, make a temporary QueryDesc with the proper
|
||||||
@ -156,9 +160,6 @@ PerformPortalFetch(char *name,
|
|||||||
* original dest. This is necessary since a FETCH command will pass
|
* original dest. This is necessary since a FETCH command will pass
|
||||||
* dest = Remote, not knowing whether the cursor is binary or not.
|
* dest = Remote, not knowing whether the cursor is binary or not.
|
||||||
*/
|
*/
|
||||||
queryDesc = PortalGetQueryDesc(portal);
|
|
||||||
estate = PortalGetState(portal);
|
|
||||||
|
|
||||||
if (dest != queryDesc->dest &&
|
if (dest != queryDesc->dest &&
|
||||||
!(queryDesc->dest == RemoteInternal && dest == Remote))
|
!(queryDesc->dest == RemoteInternal && dest == Remote))
|
||||||
{
|
{
|
||||||
@ -170,19 +171,6 @@ PerformPortalFetch(char *name,
|
|||||||
temp_desc = true;
|
temp_desc = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Tell the destination to prepare to receive some tuples.
|
|
||||||
*/
|
|
||||||
BeginCommand(name,
|
|
||||||
queryDesc->operation,
|
|
||||||
PortalGetTupleDesc(portal),
|
|
||||||
false, /* portal fetches don't end up in
|
|
||||||
* relations */
|
|
||||||
false, /* this is a portal fetch, not a "retrieve
|
|
||||||
* portal" */
|
|
||||||
NULL, /* not used */
|
|
||||||
queryDesc->dest);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore the scanCommandId that was current when the cursor was
|
* Restore the scanCommandId that was current when the cursor was
|
||||||
* opened. This ensures that we see the same tuples throughout the
|
* opened. This ensures that we see the same tuples throughout the
|
||||||
@ -194,47 +182,49 @@ PerformPortalFetch(char *name,
|
|||||||
/*
|
/*
|
||||||
* Determine which direction to go in, and check to see if we're
|
* Determine which direction to go in, and check to see if we're
|
||||||
* already at the end of the available tuples in that direction. If
|
* already at the end of the available tuples in that direction. If
|
||||||
* so, do nothing. (This check exists because not all plan node types
|
* so, set the direction to NoMovement to avoid trying to fetch any
|
||||||
|
* tuples. (This check exists because not all plan node types
|
||||||
* are robust about being called again if they've already returned
|
* are robust about being called again if they've already returned
|
||||||
* NULL once.) If it's OK to do the fetch, call the executor. Then,
|
* NULL once.) Then call the executor (we must not skip this, because
|
||||||
* update the atStart/atEnd state depending on the number of tuples
|
* the destination needs to see a setup and shutdown even if no tuples
|
||||||
* that were retrieved.
|
* are available). Finally, update the atStart/atEnd state depending
|
||||||
|
* on the number of tuples that were retrieved.
|
||||||
*/
|
*/
|
||||||
if (forward)
|
if (forward)
|
||||||
{
|
{
|
||||||
if (!portal->atEnd)
|
if (portal->atEnd)
|
||||||
{
|
direction = NoMovementScanDirection;
|
||||||
ExecutorRun(queryDesc, estate, EXEC_FOR, (long) count);
|
else
|
||||||
|
direction = ForwardScanDirection;
|
||||||
|
|
||||||
if (estate->es_processed > 0)
|
ExecutorRun(queryDesc, estate, direction, (long) count);
|
||||||
portal->atStart = false; /* OK to back up now */
|
|
||||||
if (count <= 0 || (int) estate->es_processed < count)
|
|
||||||
portal->atEnd = true; /* we retrieved 'em all */
|
|
||||||
|
|
||||||
if (completionTag)
|
if (estate->es_processed > 0)
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
|
portal->atStart = false; /* OK to back up now */
|
||||||
(dest == None) ? "MOVE" : "FETCH",
|
if (count <= 0 || (int) estate->es_processed < count)
|
||||||
estate->es_processed);
|
portal->atEnd = true; /* we retrieved 'em all */
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!portal->atStart)
|
if (portal->atStart)
|
||||||
{
|
direction = NoMovementScanDirection;
|
||||||
ExecutorRun(queryDesc, estate, EXEC_BACK, (long) count);
|
else
|
||||||
|
direction = BackwardScanDirection;
|
||||||
|
|
||||||
if (estate->es_processed > 0)
|
ExecutorRun(queryDesc, estate, direction, (long) count);
|
||||||
portal->atEnd = false; /* OK to go forward now */
|
|
||||||
if (count <= 0 || (int) estate->es_processed < count)
|
|
||||||
portal->atStart = true; /* we retrieved 'em all */
|
|
||||||
|
|
||||||
if (completionTag)
|
if (estate->es_processed > 0)
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
|
portal->atEnd = false; /* OK to go forward now */
|
||||||
(dest == None) ? "MOVE" : "FETCH",
|
if (count <= 0 || (int) estate->es_processed < count)
|
||||||
estate->es_processed);
|
portal->atStart = true; /* we retrieved 'em all */
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return command status if wanted */
|
||||||
|
if (completionTag)
|
||||||
|
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
|
||||||
|
(dest == None) ? "MOVE" : "FETCH",
|
||||||
|
estate->es_processed);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore outer command ID.
|
* Restore outer command ID.
|
||||||
*/
|
*/
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
* query plan and ExecutorEnd() should always be called at the end of
|
* query plan and ExecutorEnd() should always be called at the end of
|
||||||
* execution of a plan.
|
* execution of a plan.
|
||||||
*
|
*
|
||||||
* ExecutorRun accepts 'feature' and 'count' arguments that specify whether
|
* ExecutorRun accepts direction and count arguments that specify whether
|
||||||
* the plan is to be executed forwards, backwards, and for how many tuples.
|
* the plan is to be executed forwards, backwards, and for how many tuples.
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
@ -27,7 +27,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.149 2001/10/25 05:49:27 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.150 2002/02/27 19:34:48 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -88,7 +88,7 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
|
|||||||
* query plan
|
* query plan
|
||||||
*
|
*
|
||||||
* returns a TupleDesc which describes the attributes of the tuples to
|
* returns a TupleDesc which describes the attributes of the tuples to
|
||||||
* be returned by the query.
|
* be returned by the query. (Same value is saved in queryDesc)
|
||||||
*
|
*
|
||||||
* NB: the CurrentMemoryContext when this is called must be the context
|
* NB: the CurrentMemoryContext when this is called must be the context
|
||||||
* to be used as the per-query context for the query plan. ExecutorRun()
|
* to be used as the per-query context for the query plan. ExecutorRun()
|
||||||
@ -137,6 +137,8 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
|
|||||||
queryDesc->plantree,
|
queryDesc->plantree,
|
||||||
estate);
|
estate);
|
||||||
|
|
||||||
|
queryDesc->tupDesc = result;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,25 +151,23 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
|
|||||||
*
|
*
|
||||||
* ExecutorStart must have been called already.
|
* ExecutorStart must have been called already.
|
||||||
*
|
*
|
||||||
* the different features supported are:
|
* If direction is NoMovementScanDirection then nothing is done
|
||||||
* EXEC_RUN: retrieve all tuples in the forward direction
|
* except to start up/shut down the destination. Otherwise,
|
||||||
* EXEC_FOR: retrieve 'count' number of tuples in the forward dir
|
* we retrieve up to 'count' tuples in the specified direction.
|
||||||
* EXEC_BACK: retrieve 'count' number of tuples in the backward dir
|
|
||||||
* EXEC_RETONE: return one tuple but don't 'retrieve' it
|
|
||||||
* used in postquel function processing
|
|
||||||
*
|
*
|
||||||
* Note: count = 0 is interpreted as "no limit".
|
* Note: count = 0 is interpreted as "no limit".
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count)
|
ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
||||||
|
ScanDirection direction, long count)
|
||||||
{
|
{
|
||||||
CmdType operation;
|
CmdType operation;
|
||||||
Plan *plan;
|
Plan *plan;
|
||||||
TupleTableSlot *result;
|
|
||||||
CommandDest dest;
|
CommandDest dest;
|
||||||
DestReceiver *destfunc;
|
DestReceiver *destfunc;
|
||||||
|
TupleTableSlot *result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
@ -181,69 +181,33 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count)
|
|||||||
operation = queryDesc->operation;
|
operation = queryDesc->operation;
|
||||||
plan = queryDesc->plantree;
|
plan = queryDesc->plantree;
|
||||||
dest = queryDesc->dest;
|
dest = queryDesc->dest;
|
||||||
destfunc = DestToFunction(dest);
|
|
||||||
|
/*
|
||||||
|
* startup tuple receiver
|
||||||
|
*/
|
||||||
estate->es_processed = 0;
|
estate->es_processed = 0;
|
||||||
estate->es_lastoid = InvalidOid;
|
estate->es_lastoid = InvalidOid;
|
||||||
|
|
||||||
|
destfunc = DestToFunction(dest);
|
||||||
|
(*destfunc->setup) (destfunc, (int) operation,
|
||||||
|
queryDesc->portalName, queryDesc->tupDesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: the dest setup function ought to be handed the tuple desc
|
* run plan
|
||||||
* 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);
|
if (direction == NoMovementScanDirection)
|
||||||
|
result = NULL;
|
||||||
switch (feature)
|
else
|
||||||
{
|
result = ExecutePlan(estate,
|
||||||
case EXEC_RUN:
|
plan,
|
||||||
result = ExecutePlan(estate,
|
operation,
|
||||||
plan,
|
count,
|
||||||
operation,
|
direction,
|
||||||
count,
|
destfunc);
|
||||||
ForwardScanDirection,
|
|
||||||
destfunc);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EXEC_FOR:
|
|
||||||
result = ExecutePlan(estate,
|
|
||||||
plan,
|
|
||||||
operation,
|
|
||||||
count,
|
|
||||||
ForwardScanDirection,
|
|
||||||
destfunc);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* retrieve next n "backward" tuples
|
|
||||||
*/
|
|
||||||
case EXEC_BACK:
|
|
||||||
result = ExecutePlan(estate,
|
|
||||||
plan,
|
|
||||||
operation,
|
|
||||||
count,
|
|
||||||
BackwardScanDirection,
|
|
||||||
destfunc);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* return one tuple but don't "retrieve" it. (this is used by
|
|
||||||
* the rule manager..) -cim 9/14/89
|
|
||||||
*/
|
|
||||||
case EXEC_RETONE:
|
|
||||||
result = ExecutePlan(estate,
|
|
||||||
plan,
|
|
||||||
operation,
|
|
||||||
ONE_TUPLE,
|
|
||||||
ForwardScanDirection,
|
|
||||||
destfunc);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
|
|
||||||
result = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* shutdown receiver
|
||||||
|
*/
|
||||||
(*destfunc->cleanup) (destfunc);
|
(*destfunc->cleanup) (destfunc);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -916,7 +880,7 @@ EndPlan(Plan *plan, EState *estate)
|
|||||||
*
|
*
|
||||||
* processes the query plan to retrieve 'numberTuples' tuples in the
|
* processes the query plan to retrieve 'numberTuples' tuples in the
|
||||||
* direction specified.
|
* direction specified.
|
||||||
* Retrieves all tuples if tupleCount is 0
|
* Retrieves all tuples if numberTuples is 0
|
||||||
*
|
*
|
||||||
* result is either a slot containing the last tuple in the case
|
* result is either a slot containing the last tuple in the case
|
||||||
* of a RETRIEVE or NULL otherwise.
|
* of a RETRIEVE or NULL otherwise.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.48 2002/02/26 22:47:05 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.49 2002/02/27 19:34:51 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -111,9 +111,8 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
|
|||||||
|
|
||||||
nextes->next = NULL;
|
nextes->next = NULL;
|
||||||
nextes->status = F_EXEC_START;
|
nextes->status = F_EXEC_START;
|
||||||
nextes->qd = CreateQueryDesc(queryTree,
|
|
||||||
planTree,
|
nextes->qd = CreateQueryDesc(queryTree, planTree, None, NULL);
|
||||||
None);
|
|
||||||
estate = CreateExecutorState();
|
estate = CreateExecutorState();
|
||||||
|
|
||||||
if (nargs > 0)
|
if (nargs > 0)
|
||||||
@ -268,7 +267,7 @@ postquel_start(execution_state *es)
|
|||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
postquel_getnext(execution_state *es)
|
postquel_getnext(execution_state *es)
|
||||||
{
|
{
|
||||||
int feature;
|
long count;
|
||||||
|
|
||||||
if (es->qd->operation == CMD_UTILITY)
|
if (es->qd->operation == CMD_UTILITY)
|
||||||
{
|
{
|
||||||
@ -281,9 +280,10 @@ postquel_getnext(execution_state *es)
|
|||||||
return (TupleTableSlot *) NULL;
|
return (TupleTableSlot *) NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
|
/* If it's not the last command, just run it to completion */
|
||||||
|
count = (LAST_POSTQUEL_COMMAND(es)) ? 1L : 0L;
|
||||||
|
|
||||||
return ExecutorRun(es->qd, es->estate, feature, 0L);
|
return ExecutorRun(es->qd, es->estate, ForwardScanDirection, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.66 2002/02/26 22:47:05 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.67 2002/02/27 19:34:59 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -779,7 +779,7 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
|
|||||||
queryTree->isBinary = false;
|
queryTree->isBinary = false;
|
||||||
|
|
||||||
/* Create the QueryDesc object and the executor state */
|
/* Create the QueryDesc object and the executor state */
|
||||||
queryDesc = CreateQueryDesc(queryTree, planTree, SPI);
|
queryDesc = CreateQueryDesc(queryTree, planTree, SPI, NULL);
|
||||||
eState = CreateExecutorState();
|
eState = CreateExecutorState();
|
||||||
|
|
||||||
/* If the plan has parameters, put them into the executor state */
|
/* If the plan has parameters, put them into the executor state */
|
||||||
@ -1023,7 +1023,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
|||||||
else if (plan == NULL)
|
else if (plan == NULL)
|
||||||
{
|
{
|
||||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||||
islastquery ? SPI : None);
|
islastquery ? SPI : None, NULL);
|
||||||
state = CreateExecutorState();
|
state = CreateExecutorState();
|
||||||
res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0);
|
res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0);
|
||||||
if (res < 0 || islastquery)
|
if (res < 0 || islastquery)
|
||||||
@ -1033,7 +1033,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||||
islastquery ? SPI : None);
|
islastquery ? SPI : None, NULL);
|
||||||
res = _SPI_pquery(qdesc, NULL, islastquery ? tcount : 0);
|
res = _SPI_pquery(qdesc, NULL, islastquery ? tcount : 0);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
@ -1094,7 +1094,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||||
islastquery ? SPI : None);
|
islastquery ? SPI : None, NULL);
|
||||||
state = CreateExecutorState();
|
state = CreateExecutorState();
|
||||||
if (nargs > 0)
|
if (nargs > 0)
|
||||||
{
|
{
|
||||||
@ -1132,7 +1132,6 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||||||
Query *parseTree = queryDesc->parsetree;
|
Query *parseTree = queryDesc->parsetree;
|
||||||
int operation = queryDesc->operation;
|
int operation = queryDesc->operation;
|
||||||
CommandDest dest = queryDesc->dest;
|
CommandDest dest = queryDesc->dest;
|
||||||
TupleDesc tupdesc;
|
|
||||||
bool isRetrieveIntoPortal = false;
|
bool isRetrieveIntoPortal = false;
|
||||||
bool isRetrieveIntoRelation = false;
|
bool isRetrieveIntoRelation = false;
|
||||||
char *intoName = NULL;
|
char *intoName = NULL;
|
||||||
@ -1174,11 +1173,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||||||
|
|
||||||
if (state == NULL) /* plan preparation */
|
if (state == NULL) /* plan preparation */
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
#ifdef SPI_EXECUTOR_STATS
|
#ifdef SPI_EXECUTOR_STATS
|
||||||
if (ShowExecutorStats)
|
if (ShowExecutorStats)
|
||||||
ResetUsage();
|
ResetUsage();
|
||||||
#endif
|
#endif
|
||||||
tupdesc = ExecutorStart(queryDesc, state);
|
|
||||||
|
ExecutorStart(queryDesc, state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't work currently --- need to rearrange callers so that we
|
* Don't work currently --- need to rearrange callers so that we
|
||||||
@ -1188,7 +1189,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||||||
if (isRetrieveIntoPortal)
|
if (isRetrieveIntoPortal)
|
||||||
elog(FATAL, "SPI_select: retrieve into portal not implemented");
|
elog(FATAL, "SPI_select: retrieve into portal not implemented");
|
||||||
|
|
||||||
ExecutorRun(queryDesc, state, EXEC_FOR, (long) tcount);
|
ExecutorRun(queryDesc, state, ForwardScanDirection, (long) tcount);
|
||||||
|
|
||||||
_SPI_current->processed = state->es_processed;
|
_SPI_current->processed = state->es_processed;
|
||||||
save_lastoid = state->es_lastoid;
|
save_lastoid = state->es_lastoid;
|
||||||
@ -1230,6 +1231,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||||||
QueryDesc *querydesc;
|
QueryDesc *querydesc;
|
||||||
EState *estate;
|
EState *estate;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
|
ScanDirection direction;
|
||||||
CommandId savedId;
|
CommandId savedId;
|
||||||
CommandDest olddest;
|
CommandDest olddest;
|
||||||
|
|
||||||
@ -1268,29 +1270,35 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||||||
/* Run the executor like PerformPortalFetch and remember states */
|
/* Run the executor like PerformPortalFetch and remember states */
|
||||||
if (forward)
|
if (forward)
|
||||||
{
|
{
|
||||||
if (!portal->atEnd)
|
if (portal->atEnd)
|
||||||
{
|
direction = NoMovementScanDirection;
|
||||||
ExecutorRun(querydesc, estate, EXEC_FOR, (long) count);
|
else
|
||||||
_SPI_current->processed = estate->es_processed;
|
direction = ForwardScanDirection;
|
||||||
if (estate->es_processed > 0)
|
|
||||||
portal->atStart = false;
|
ExecutorRun(querydesc, estate, direction, (long) count);
|
||||||
if (count <= 0 || (int) estate->es_processed < count)
|
|
||||||
portal->atEnd = true;
|
if (estate->es_processed > 0)
|
||||||
}
|
portal->atStart = false; /* OK to back up now */
|
||||||
|
if (count <= 0 || (int) estate->es_processed < count)
|
||||||
|
portal->atEnd = true; /* we retrieved 'em all */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!portal->atStart)
|
if (portal->atStart)
|
||||||
{
|
direction = NoMovementScanDirection;
|
||||||
ExecutorRun(querydesc, estate, EXEC_BACK, (long) count);
|
else
|
||||||
_SPI_current->processed = estate->es_processed;
|
direction = BackwardScanDirection;
|
||||||
if (estate->es_processed > 0)
|
|
||||||
portal->atEnd = false;
|
ExecutorRun(querydesc, estate, direction, (long) count);
|
||||||
if (count <= 0 || estate->es_processed < count)
|
|
||||||
portal->atStart = true;
|
if (estate->es_processed > 0)
|
||||||
}
|
portal->atEnd = false; /* OK to go forward now */
|
||||||
|
if (count <= 0 || (int) estate->es_processed < count)
|
||||||
|
portal->atStart = true; /* we retrieved 'em all */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_SPI_current->processed = estate->es_processed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore outer command ID.
|
* Restore outer command ID.
|
||||||
*/
|
*/
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* dest.c
|
* dest.c
|
||||||
* support for various communication destinations - see include/tcop/dest.h
|
* support for communication destinations
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* 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.47 2002/02/26 22:47:08 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.48 2002/02/27 19:35:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
* BeginCommand - prepare destination for tuples of the given type
|
* BeginCommand - initialize the destination at start of command
|
||||||
* DestToFunction - identify per-tuple processing routines
|
* DestToFunction - identify per-tuple processing routines
|
||||||
* EndCommand - tell destination that no more tuples will arrive
|
* EndCommand - clean up the destination at end of command
|
||||||
* 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
|
||||||
*
|
*
|
||||||
@ -24,14 +24,6 @@
|
|||||||
* These routines do the appropriate work before and after
|
* These routines do the appropriate work before and after
|
||||||
* 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 "postgres.h"
|
#include "postgres.h"
|
||||||
@ -51,7 +43,8 @@ donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
donothingSetup(DestReceiver *self, TupleDesc typeinfo)
|
donothingSetup(DestReceiver *self, int operation,
|
||||||
|
const char *portalName, TupleDesc typeinfo)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,97 +61,20 @@ static DestReceiver donothingDR = {
|
|||||||
donothingReceive, donothingSetup, donothingCleanup
|
donothingReceive, donothingSetup, donothingCleanup
|
||||||
};
|
};
|
||||||
static DestReceiver debugtupDR = {
|
static DestReceiver debugtupDR = {
|
||||||
debugtup, donothingSetup, donothingCleanup
|
debugtup, debugSetup, donothingCleanup
|
||||||
};
|
};
|
||||||
static DestReceiver spi_printtupDR = {
|
static DestReceiver spi_printtupDR = {
|
||||||
spi_printtup, donothingSetup, donothingCleanup
|
spi_printtup, donothingSetup, donothingCleanup
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* BeginCommand - prepare destination for tuples of the given type
|
* BeginCommand - initialize the destination at start of command
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
BeginCommand(char *pname,
|
BeginCommand(const char *commandTag, CommandDest dest)
|
||||||
int operation,
|
|
||||||
TupleDesc tupdesc,
|
|
||||||
bool isIntoRel,
|
|
||||||
bool isIntoPortal,
|
|
||||||
char *tag,
|
|
||||||
CommandDest dest)
|
|
||||||
{
|
{
|
||||||
Form_pg_attribute *attrs = tupdesc->attrs;
|
/* Nothing to do at present */
|
||||||
int natts = tupdesc->natts;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
switch (dest)
|
|
||||||
{
|
|
||||||
case Remote:
|
|
||||||
case RemoteInternal:
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if this is a "retrieve into portal" query, done because
|
|
||||||
* nothing needs to be sent to the fe.
|
|
||||||
*/
|
|
||||||
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_puttextmessage('P', pname);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
StringInfoData buf;
|
|
||||||
|
|
||||||
pq_beginmessage(&buf);
|
|
||||||
pq_sendbyte(&buf, 'T'); /* tuple descriptor message type */
|
|
||||||
pq_sendint(&buf, natts, 2); /* # of attributes in
|
|
||||||
* tuples */
|
|
||||||
|
|
||||||
for (i = 0; i < natts; ++i)
|
|
||||||
{
|
|
||||||
pq_sendstring(&buf, NameStr(attrs[i]->attname));
|
|
||||||
pq_sendint(&buf, (int) attrs[i]->atttypid,
|
|
||||||
sizeof(attrs[i]->atttypid));
|
|
||||||
pq_sendint(&buf, attrs[i]->attlen,
|
|
||||||
sizeof(attrs[i]->attlen));
|
|
||||||
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
|
|
||||||
pq_sendint(&buf, attrs[i]->atttypmod,
|
|
||||||
sizeof(attrs[i]->atttypmod));
|
|
||||||
}
|
|
||||||
pq_endmessage(&buf);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Debug:
|
|
||||||
|
|
||||||
/*
|
|
||||||
* show the return type of the tuples
|
|
||||||
*/
|
|
||||||
if (pname == NULL)
|
|
||||||
pname = "blank";
|
|
||||||
|
|
||||||
showatts(pname, tupdesc);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case None:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -183,19 +99,15 @@ DestToFunction(CommandDest dest)
|
|||||||
return &spi_printtupDR;
|
return &spi_printtupDR;
|
||||||
|
|
||||||
case None:
|
case None:
|
||||||
default:
|
|
||||||
return &donothingDR;
|
return &donothingDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* should never get here */
|
||||||
* never gets here, but DECstation lint appears to be stupid...
|
|
||||||
*/
|
|
||||||
|
|
||||||
return &donothingDR;
|
return &donothingDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* EndCommand - tell destination that query is complete
|
* EndCommand - clean up the destination at end of command
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.248 2002/02/26 22:47:08 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.249 2002/02/27 19:35:12 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* this is the "main" module of the postgres backend and
|
* this is the "main" module of the postgres backend and
|
||||||
@ -645,6 +645,18 @@ pg_exec_query_string(char *query_string, /* string to execute */
|
|||||||
/* Transaction control statements need some special handling */
|
/* Transaction control statements need some special handling */
|
||||||
isTransactionStmt = IsA(parsetree, TransactionStmt);
|
isTransactionStmt = IsA(parsetree, TransactionStmt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First we set the command-completion tag to the main query
|
||||||
|
* (as opposed to each of the others that may be generated by
|
||||||
|
* analyze and rewrite). Also set ps_status and do any special
|
||||||
|
* start-of-SQL-command processing needed by the destination.
|
||||||
|
*/
|
||||||
|
commandTag = CreateCommandTag(parsetree);
|
||||||
|
|
||||||
|
set_ps_display(commandTag);
|
||||||
|
|
||||||
|
BeginCommand(commandTag, dest);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are in an aborted transaction, ignore all commands except
|
* If we are in an aborted transaction, ignore all commands except
|
||||||
* COMMIT/ABORT. It is important that this test occur before we
|
* COMMIT/ABORT. It is important that this test occur before we
|
||||||
@ -707,18 +719,7 @@ pg_exec_query_string(char *query_string, /* string to execute */
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* OK to analyze and rewrite this query.
|
* OK to analyze and rewrite this query.
|
||||||
*/
|
*
|
||||||
|
|
||||||
/*
|
|
||||||
* First we set the command-completion tag to the main query
|
|
||||||
* (as opposed to each of the others that may be generated by
|
|
||||||
* analyze and rewrite). Also set ps_status to the main query tag.
|
|
||||||
*/
|
|
||||||
commandTag = CreateCommandTag(parsetree);
|
|
||||||
|
|
||||||
set_ps_display(commandTag);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Switch to appropriate context for constructing querytrees (again,
|
* Switch to appropriate context for constructing querytrees (again,
|
||||||
* these must outlive the execution context).
|
* these must outlive the execution context).
|
||||||
*/
|
*/
|
||||||
@ -1688,7 +1689,7 @@ PostgresMain(int argc, char *argv[], const char *username)
|
|||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
puts("\nPOSTGRES backend interactive interface ");
|
puts("\nPOSTGRES backend interactive interface ");
|
||||||
puts("$Revision: 1.248 $ $Date: 2002/02/26 22:47:08 $\n");
|
puts("$Revision: 1.249 $ $Date: 2002/02/27 19:35:12 $\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.47 2002/02/26 22:47:09 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.48 2002/02/27 19:35:16 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -30,7 +30,8 @@
|
|||||||
QueryDesc *
|
QueryDesc *
|
||||||
CreateQueryDesc(Query *parsetree,
|
CreateQueryDesc(Query *parsetree,
|
||||||
Plan *plantree,
|
Plan *plantree,
|
||||||
CommandDest dest)
|
CommandDest dest,
|
||||||
|
const char *portalName)
|
||||||
{
|
{
|
||||||
QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
|
QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
|
||||||
|
|
||||||
@ -38,6 +39,9 @@ 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->tupDesc = NULL; /* until set by ExecutorStart */
|
||||||
|
|
||||||
return qd;
|
return qd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,8 +142,7 @@ ProcessQuery(Query *parsetree,
|
|||||||
char *completionTag)
|
char *completionTag)
|
||||||
{
|
{
|
||||||
int operation = parsetree->commandType;
|
int operation = parsetree->commandType;
|
||||||
bool isRetrieveIntoPortal;
|
bool isRetrieveIntoPortal = false;
|
||||||
bool isRetrieveIntoRelation;
|
|
||||||
char *intoName = NULL;
|
char *intoName = NULL;
|
||||||
Portal portal = NULL;
|
Portal portal = NULL;
|
||||||
MemoryContext oldContext = NULL;
|
MemoryContext oldContext = NULL;
|
||||||
@ -148,31 +151,28 @@ ProcessQuery(Query *parsetree,
|
|||||||
TupleDesc attinfo;
|
TupleDesc attinfo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize portal/into relation status
|
* Check for special-case destinations
|
||||||
*/
|
*/
|
||||||
isRetrieveIntoPortal = false;
|
|
||||||
isRetrieveIntoRelation = false;
|
|
||||||
|
|
||||||
if (operation == CMD_SELECT)
|
if (operation == CMD_SELECT)
|
||||||
{
|
{
|
||||||
if (parsetree->isPortal)
|
if (parsetree->isPortal)
|
||||||
{
|
{
|
||||||
isRetrieveIntoPortal = true;
|
isRetrieveIntoPortal = true;
|
||||||
intoName = parsetree->into;
|
intoName = parsetree->into;
|
||||||
if (parsetree->isBinary)
|
/* If binary portal, switch to alternate output format */
|
||||||
{
|
if (dest == Remote && parsetree->isBinary)
|
||||||
/*
|
|
||||||
* For internal format portals, we change Remote
|
|
||||||
* (externalized form) to RemoteInternal (internalized
|
|
||||||
* form)
|
|
||||||
*/
|
|
||||||
dest = RemoteInternal;
|
dest = RemoteInternal;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (parsetree->into != NULL)
|
else if (parsetree->into != NULL)
|
||||||
{
|
{
|
||||||
/* select into table */
|
/*
|
||||||
isRetrieveIntoRelation = true;
|
* SELECT INTO table (a/k/a CREATE AS ... SELECT).
|
||||||
|
*
|
||||||
|
* Override the normal communication destination; execMain.c
|
||||||
|
* special-cases this case. (Perhaps would be cleaner to
|
||||||
|
* have an additional destination type?)
|
||||||
|
*/
|
||||||
|
dest = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,16 +197,7 @@ ProcessQuery(Query *parsetree,
|
|||||||
/*
|
/*
|
||||||
* Now we can create the QueryDesc object.
|
* Now we can create the QueryDesc object.
|
||||||
*/
|
*/
|
||||||
queryDesc = CreateQueryDesc(parsetree, plan, dest);
|
queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName);
|
||||||
|
|
||||||
/*
|
|
||||||
* When performing a retrieve into, we override the normal
|
|
||||||
* communication destination during the processing of the the query.
|
|
||||||
* This only affects the tuple-output function - the correct
|
|
||||||
* destination will still see the BeginCommand() call.
|
|
||||||
*/
|
|
||||||
if (isRetrieveIntoRelation)
|
|
||||||
queryDesc->dest = None;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create a default executor state.
|
* create a default executor state.
|
||||||
@ -218,18 +209,6 @@ ProcessQuery(Query *parsetree,
|
|||||||
*/
|
*/
|
||||||
attinfo = ExecutorStart(queryDesc, state);
|
attinfo = ExecutorStart(queryDesc, state);
|
||||||
|
|
||||||
/*
|
|
||||||
* report the query's result type information back to the front end or
|
|
||||||
* to whatever destination we're dealing with.
|
|
||||||
*/
|
|
||||||
BeginCommand(NULL,
|
|
||||||
operation,
|
|
||||||
attinfo,
|
|
||||||
isRetrieveIntoRelation,
|
|
||||||
isRetrieveIntoPortal,
|
|
||||||
NULL, /* not used */
|
|
||||||
dest);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If retrieve into portal, stop now; we do not run the plan until a
|
* If retrieve into portal, stop now; we do not run the plan until a
|
||||||
* FETCH command is received.
|
* FETCH command is received.
|
||||||
@ -256,7 +235,7 @@ ProcessQuery(Query *parsetree,
|
|||||||
* Now we get to the important call to ExecutorRun() where we actually
|
* Now we get to the important call to ExecutorRun() where we actually
|
||||||
* run the plan..
|
* run the plan..
|
||||||
*/
|
*/
|
||||||
ExecutorRun(queryDesc, state, EXEC_RUN, 0L);
|
ExecutorRun(queryDesc, state, ForwardScanDirection, 0L);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build command completion status string, if caller wants one.
|
* Build command completion status string, if caller wants one.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.45 2002/02/14 15:24:09 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.46 2002/02/27 19:35:35 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -22,8 +22,8 @@
|
|||||||
* sees a
|
* sees a
|
||||||
* fetch 1 from FOO
|
* fetch 1 from FOO
|
||||||
* the system looks up the portal named "FOO" in the portal table,
|
* the system looks up the portal named "FOO" in the portal table,
|
||||||
* gets the planned query and then calls the executor with a feature of
|
* gets the planned query and then calls the executor with a count
|
||||||
* '(EXEC_FOR 1). The executor then runs the query and returns a single
|
* of 1. The executor then runs the query and returns a single
|
||||||
* tuple. The problem is that we have to hold onto the state of the
|
* tuple. The problem is that we have to hold onto the state of the
|
||||||
* portal query until we see a "close". This means we have to be
|
* portal query until we see a "close". This means we have to be
|
||||||
* careful about memory management.
|
* careful about memory management.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, 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.18 2001/11/05 17:46:31 momjian Exp $
|
* $Id: printtup.h,v 1.19 2002/02/27 19:35:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -18,9 +18,10 @@
|
|||||||
|
|
||||||
extern DestReceiver *printtup_create_DR(bool isBinary);
|
extern DestReceiver *printtup_create_DR(bool isBinary);
|
||||||
|
|
||||||
extern void showatts(char *name, TupleDesc attinfo);
|
extern void debugSetup(DestReceiver *self, int operation,
|
||||||
|
const char *portalName, TupleDesc typeinfo);
|
||||||
extern void debugtup(HeapTuple tuple, TupleDesc typeinfo,
|
extern void debugtup(HeapTuple tuple, TupleDesc typeinfo,
|
||||||
DestReceiver *self);
|
DestReceiver *self);
|
||||||
|
|
||||||
/* XXX this one is really in executor/spi.c */
|
/* XXX this one is really in executor/spi.c */
|
||||||
extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc,
|
extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc,
|
||||||
|
@ -7,30 +7,13 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, 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: execdefs.h,v 1.11 2001/11/05 17:46:33 momjian Exp $
|
* $Id: execdefs.h,v 1.12 2002/02/27 19:35:51 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#ifndef EXECDEFS_H
|
#ifndef EXECDEFS_H
|
||||||
#define EXECDEFS_H
|
#define EXECDEFS_H
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* ExecutePlan() tuplecount definitions
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
#define ALL_TUPLES 0 /* return all tuples */
|
|
||||||
#define ONE_TUPLE 1 /* return only one tuple */
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* constants used by ExecMain
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
#define EXEC_RUN 3
|
|
||||||
#define EXEC_FOR 4
|
|
||||||
#define EXEC_BACK 5
|
|
||||||
#define EXEC_RETONE 6
|
|
||||||
#define EXEC_RESULT 7
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Merge Join states
|
* Merge Join states
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, 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.17 2001/11/05 17:46:33 momjian Exp $
|
* $Id: execdesc.h,v 1.18 2002/02/27 19:35:54 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#include "nodes/plannodes.h"
|
#include "nodes/plannodes.h"
|
||||||
#include "tcop/dest.h"
|
#include "tcop/dest.h"
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* query descriptor:
|
* query descriptor:
|
||||||
* a QueryDesc encapsulates everything that the executor
|
* a QueryDesc encapsulates everything that the executor
|
||||||
@ -31,10 +32,14 @@ typedef struct QueryDesc
|
|||||||
Query *parsetree;
|
Query *parsetree;
|
||||||
Plan *plantree;
|
Plan *plantree;
|
||||||
CommandDest dest; /* the destination output of the execution */
|
CommandDest dest; /* the destination output of the execution */
|
||||||
|
const char *portalName; /* name of portal, or NULL */
|
||||||
|
|
||||||
|
TupleDesc tupDesc; /* set by ExecutorStart */
|
||||||
} QueryDesc;
|
} QueryDesc;
|
||||||
|
|
||||||
/* in pquery.c */
|
/* in pquery.c */
|
||||||
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
|
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
|
||||||
CommandDest dest);
|
CommandDest dest, const char *portalName);
|
||||||
|
|
||||||
|
|
||||||
#endif /* EXECDESC_H */
|
#endif /* EXECDESC_H */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, 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: executor.h,v 1.62 2002/02/19 20:11:19 tgl Exp $
|
* $Id: executor.h,v 1.63 2002/02/27 19:35:59 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -50,7 +50,7 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
|
|||||||
*/
|
*/
|
||||||
extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
|
extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
|
||||||
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
||||||
int feature, long count);
|
ScanDirection direction, long count);
|
||||||
extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
|
extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
|
||||||
extern void ExecConstraints(char *caller, ResultRelInfo *resultRelInfo,
|
extern void ExecConstraints(char *caller, ResultRelInfo *resultRelInfo,
|
||||||
TupleTableSlot *slot, EState *estate);
|
TupleTableSlot *slot, EState *estate);
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* dest.h
|
* dest.h
|
||||||
* Whenever the backend executes a query, the results
|
* support for communication destinations
|
||||||
* have to go someplace.
|
*
|
||||||
|
* Whenever the backend executes a query, the results
|
||||||
|
* have to go someplace.
|
||||||
*
|
*
|
||||||
* - stdout is the destination only when we are running a
|
* - stdout is the destination only when we are running a
|
||||||
* backend without a postmaster and are returning results
|
* standalone backend (no postmaster) and are returning results
|
||||||
* back to an interactive user.
|
* back to an interactive user.
|
||||||
*
|
*
|
||||||
* - a remote process is the destination when we are
|
* - a remote process is the destination when we are
|
||||||
@ -14,15 +16,21 @@
|
|||||||
* to the frontend via the functions in backend/libpq.
|
* to the frontend via the functions in backend/libpq.
|
||||||
*
|
*
|
||||||
* - None is the destination when the system executes
|
* - None is the destination when the system executes
|
||||||
* a query internally. This is not used now but it may be
|
* a query internally. The results are discarded.
|
||||||
* useful for the parallel optimiser/executor.
|
|
||||||
*
|
*
|
||||||
* dest.c defines three functions that implement destination management:
|
* dest.c defines three functions that implement destination management:
|
||||||
*
|
*
|
||||||
* BeginCommand: initialize the destination.
|
* BeginCommand: initialize the destination at start of command.
|
||||||
* DestToFunction: return a pointer to a struct of destination-specific
|
* DestToFunction: return a pointer to a struct of destination-specific
|
||||||
* receiver functions.
|
* receiver functions.
|
||||||
* EndCommand: clean up the destination when output is complete.
|
* EndCommand: clean up the destination at end of command.
|
||||||
|
*
|
||||||
|
* BeginCommand/EndCommand are executed once per received SQL query.
|
||||||
|
*
|
||||||
|
* DestToFunction, and the receiver functions it links to, are executed
|
||||||
|
* each time we run the executor to produce tuples, which may occur
|
||||||
|
* multiple times per received query (eg, due to additional queries produced
|
||||||
|
* by rewrite rules).
|
||||||
*
|
*
|
||||||
* The DestReceiver object returned by DestToFunction may be a statically
|
* The DestReceiver object returned by DestToFunction may be a statically
|
||||||
* allocated object (for destination types that require no local state)
|
* allocated object (for destination types that require no local state)
|
||||||
@ -32,14 +40,11 @@
|
|||||||
* by casting the DestReceiver* pointer passed to them.
|
* by casting the DestReceiver* pointer passed to them.
|
||||||
* The palloc'd object is pfree'd by the DestReceiver's cleanup function.
|
* 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.
|
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, 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.29 2002/02/26 22:47:11 tgl Exp $
|
* $Id: dest.h,v 1.30 2002/02/27 19:36:13 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -80,18 +85,17 @@ 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);
|
||||||
/* Initialization and teardown: */
|
/* Initialization and teardown: */
|
||||||
void (*setup) (DestReceiver *self, TupleDesc typeinfo);
|
void (*setup) (DestReceiver *self, int operation,
|
||||||
|
const char *portalName, TupleDesc typeinfo);
|
||||||
void (*cleanup) (DestReceiver *self);
|
void (*cleanup) (DestReceiver *self);
|
||||||
/* Private fields might appear beyond this point... */
|
/* Private fields might appear beyond this point... */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The primary destination management functions */
|
/* The primary destination management functions */
|
||||||
|
|
||||||
extern void BeginCommand(char *pname, int operation, TupleDesc attinfo,
|
extern void BeginCommand(const char *commandTag, CommandDest dest);
|
||||||
bool isIntoRel, bool isIntoPortal, char *tag,
|
|
||||||
CommandDest dest);
|
|
||||||
extern DestReceiver *DestToFunction(CommandDest dest);
|
extern DestReceiver *DestToFunction(CommandDest dest);
|
||||||
extern void EndCommand(const char *commandTag, CommandDest dest);
|
extern void EndCommand(const char *commandTag, CommandDest dest);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user