Commit de28dc9a authored by Tom Lane's avatar Tom Lane

Portal and memory management infrastructure for extended query protocol.

Both plannable queries and utility commands are now always executed
within Portals, which have been revamped so that they can handle the
load (they used to be good only for single SELECT queries).  Restructure
code to push command-completion-tag selection logic out of postgres.c,
so that it won't have to be duplicated between simple and extended queries.
initdb forced due to addition of a field to Query nodes.
parent 1940434f
......@@ -77,7 +77,9 @@ PG_FUNCTION_INFO_V1(int_enum);
/*
* Manage the aggregation state of the array
* You need to specify the correct memory context, or it will vanish!
*
* Need to specify a suitably long-lived memory context, or it will vanish!
* PortalContext isn't really right, but it's close enough.
*/
static PGARRAY *
GetPGArray(int4 state, int fAdd)
......@@ -89,14 +91,7 @@ GetPGArray(int4 state, int fAdd)
/* New array */
int cb = PGARRAY_SIZE(START_NUM);
p = (PGARRAY *) MemoryContextAlloc(TopTransactionContext, cb);
if (!p)
{
elog(ERROR, "Integer aggregator, cant allocate TopTransactionContext memory");
return 0;
}
p = (PGARRAY *) MemoryContextAlloc(PortalContext, cb);
p->a.size = cb;
p->a.ndim = 0;
p->a.flags = 0;
......@@ -115,18 +110,6 @@ GetPGArray(int4 state, int fAdd)
int cbNew = PGARRAY_SIZE(n);
pn = (PGARRAY *) repalloc(p, cbNew);
if (!pn)
{ /* Realloc failed! Reallocate new block. */
pn = (PGARRAY *) MemoryContextAlloc(TopTransactionContext, cbNew);
if (!pn)
{
elog(ERROR, "Integer aggregator, REALLY REALLY can't alloc memory");
return (PGARRAY *) NULL;
}
memcpy(pn, p, p->a.size);
pfree(p);
}
pn->a.size = cbNew;
pn->lower = n;
return pn;
......@@ -149,24 +132,19 @@ ShrinkPGArray(PGARRAY * p)
/* use current transaction context */
pnew = palloc(cb);
if (pnew)
{
/*
* Fix up the fields in the new structure, so Postgres
* understands
*/
memcpy(pnew, p, cb);
pnew->a.size = cb;
pnew->a.ndim = 1;
pnew->a.flags = 0;
/*
* Fix up the fields in the new structure, so Postgres
* understands
*/
memcpy(pnew, p, cb);
pnew->a.size = cb;
pnew->a.ndim = 1;
pnew->a.flags = 0;
#ifndef PG_7_2
pnew->a.elemtype = INT4OID;
pnew->a.elemtype = INT4OID;
#endif
pnew->lower = 0;
}
else
elog(ERROR, "Integer aggregator, can't allocate memory");
pnew->lower = 0;
pfree(p);
}
return pnew;
......
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/postgres-ref.sgml,v 1.32 2003/03/25 16:15:43 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/postgres-ref.sgml,v 1.33 2003/05/02 20:54:33 tgl Exp $
PostgreSQL documentation
-->
......@@ -28,7 +28,6 @@ PostgreSQL documentation
<arg>-E</arg>
<arg>-f<group choice="plain"><arg>s</arg><arg>i</arg><arg>t</arg><arg>n</arg><arg>m</arg><arg>h</arg></group></arg>
<arg>-F</arg>
<arg>-i</arg>
<arg>-N</arg>
<arg>-o <replaceable>filename</replaceable></arg>
<arg>-O</arg>
......@@ -52,7 +51,6 @@ PostgreSQL documentation
<arg>-e</arg>
<arg>-f<group choice="plain"><arg>s</arg><arg>i</arg><arg>t</arg><arg>n</arg><arg>m</arg><arg>h</arg></group></arg>
<arg>-F</arg>
<arg>-i</arg>
<arg>-o <replaceable>filename</replaceable></arg>
<arg>-O</arg>
<arg>-p <replaceable>database</replaceable></arg>
......@@ -281,15 +279,6 @@ PostgreSQL documentation
</listitem>
</varlistentry>
<varlistentry>
<term><option>-i</option></term>
<listitem>
<para>
Prevents query execution, but shows the plan tree.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-O</option></term>
<listitem>
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.146 2003/04/26 20:22:59 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.147 2003/05/02 20:54:33 tgl Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
......@@ -49,7 +49,7 @@
* * CleanupTransaction() executes when we finally see a user COMMIT
* or ROLLBACK command; it cleans things up and gets us out of
* the transaction internally. In particular, we mustn't destroy
* TransactionCommandContext until this point.
* TopTransactionContext until this point.
*
* NOTES
* The essential aspects of the transaction system are:
......@@ -456,13 +456,12 @@ static void
AtStart_Memory(void)
{
/*
* We shouldn't have any transaction contexts already.
* We shouldn't have a transaction context already.
*/
Assert(TopTransactionContext == NULL);
Assert(TransactionCommandContext == NULL);
/*
* Create a toplevel context for the transaction.
* Create a toplevel context for the transaction, and make it active.
*/
TopTransactionContext =
AllocSetContextCreate(TopMemoryContext,
......@@ -471,16 +470,7 @@ AtStart_Memory(void)
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/*
* Create a statement-level context and make it active.
*/
TransactionCommandContext =
AllocSetContextCreate(TopTransactionContext,
"TransactionCommandContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
MemoryContextSwitchTo(TransactionCommandContext);
MemoryContextSwitchTo(TopTransactionContext);
}
......@@ -659,7 +649,6 @@ AtCommit_Memory(void)
Assert(TopTransactionContext != NULL);
MemoryContextDelete(TopTransactionContext);
TopTransactionContext = NULL;
TransactionCommandContext = NULL;
}
/* ----------------------------------------------------------------
......@@ -769,19 +758,18 @@ AtAbort_Memory(void)
{
/*
* Make sure we are in a valid context (not a child of
* TransactionCommandContext...). Note that it is possible for this
* TopTransactionContext...). Note that it is possible for this
* code to be called when we aren't in a transaction at all; go
* directly to TopMemoryContext in that case.
*/
if (TransactionCommandContext != NULL)
if (TopTransactionContext != NULL)
{
MemoryContextSwitchTo(TransactionCommandContext);
MemoryContextSwitchTo(TopTransactionContext);
/*
* We do not want to destroy transaction contexts yet, but it
* should be OK to delete any command-local memory.
* We do not want to destroy the transaction's global state yet,
* so we can't free any memory here.
*/
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
}
else
MemoryContextSwitchTo(TopMemoryContext);
......@@ -812,7 +800,6 @@ AtCleanup_Memory(void)
if (TopTransactionContext != NULL)
MemoryContextDelete(TopTransactionContext);
TopTransactionContext = NULL;
TransactionCommandContext = NULL;
}
......@@ -926,7 +913,7 @@ CommitTransaction(void)
* access, and in fact could still cause an error...)
*/
AtEOXact_portals(true);
AtCommit_Portals();
/* handle commit for large objects [ PA, 7/17/98 ] */
/* XXX probably this does not belong here */
......@@ -1057,7 +1044,7 @@ AbortTransaction(void)
* do abort processing
*/
DeferredTriggerAbortXact();
AtEOXact_portals(false);
AtAbort_Portals();
lo_commit(false); /* 'false' means it's abort */
AtAbort_Notify();
AtEOXact_UpdatePasswordFile(false);
......@@ -1126,7 +1113,8 @@ CleanupTransaction(void)
/*
* do abort cleanup processing
*/
AtCleanup_Memory();
AtCleanup_Portals(); /* now safe to release portal memory */
AtCleanup_Memory(); /* and transaction memory */
/*
* done with abort processing, set current transaction state back to
......@@ -1220,11 +1208,11 @@ StartTransactionCommand(bool preventChain)
}
/*
* We must switch to TransactionCommandContext before returning. This
* We must switch to TopTransactionContext before returning. This
* is already done if we called StartTransaction, otherwise not.
*/
Assert(TransactionCommandContext != NULL);
MemoryContextSwitchTo(TransactionCommandContext);
Assert(TopTransactionContext != NULL);
MemoryContextSwitchTo(TopTransactionContext);
}
/*
......@@ -1266,7 +1254,6 @@ CommitTransactionCommand(bool forceCommit)
Assert(s->blockState == TBLOCK_INPROGRESS);
/* This code must match the TBLOCK_INPROGRESS case below: */
CommandCounterIncrement();
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
}
break;
......@@ -1283,15 +1270,10 @@ CommitTransactionCommand(bool forceCommit)
/*
* This is the case when we have finished executing a command
* someplace within a transaction block. We increment the
* command counter and return. Someday we may free resources
* local to the command.
*
* That someday is today, at least for memory allocated in
* TransactionCommandContext. - vadim 03/25/97
* command counter and return.
*/
case TBLOCK_INPROGRESS:
CommandCounterIncrement();
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
break;
/*
......
......@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.107 2003/03/20 03:34:55 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.108 2003/05/02 20:54:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -189,10 +189,10 @@ cluster(ClusterStmt *stmt)
/*
* Create special memory context for cross-transaction storage.
*
* Since it is a child of QueryContext, it will go away even in case
* Since it is a child of PortalContext, it will go away even in case
* of error.
*/
cluster_context = AllocSetContextCreate(QueryContext,
cluster_context = AllocSetContextCreate(PortalContext,
"Cluster",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.97 2003/01/23 15:18:40 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.98 2003/05/02 20:54:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -720,11 +720,11 @@ ReindexDatabase(const char *dbname, bool force, bool all)
/*
* Create a memory context that will survive forced transaction
* commits we do below. Since it is a child of QueryContext, it will
* commits we do below. Since it is a child of PortalContext, it will
* go away eventually even if we suffer an error; there's no need for
* special abort cleanup logic.
*/
private_context = AllocSetContextCreate(QueryContext,
private_context = AllocSetContextCreate(PortalContext,
"ReindexDatabase",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
......
This diff is collapsed.
......@@ -6,7 +6,7 @@
* Copyright (c) 2002, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.13 2003/02/02 23:46:38 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.14 2003/05/02 20:54:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -59,9 +59,8 @@ static ParamListInfo EvaluateParams(EState *estate,
void
PrepareQuery(PrepareStmt *stmt)
{
List *plan_list = NIL;
List *query_list,
*query_list_item;
*plan_list;
if (!stmt->name)
elog(ERROR, "No statement name given");
......@@ -69,19 +68,18 @@ PrepareQuery(PrepareStmt *stmt)
if (stmt->query->commandType == CMD_UTILITY)
elog(ERROR, "Utility statements cannot be prepared");
/*
* Parse analysis is already done, but we must still rewrite and plan
* the query.
*/
/* Rewrite the query. The result could be 0, 1, or many queries. */
query_list = QueryRewrite(stmt->query);
foreach(query_list_item, query_list)
{
Query *query = (Query *) lfirst(query_list_item);
Plan *plan;
plan = pg_plan_query(query);
plan_list = lappend(plan_list, plan);
}
/* Generate plans for queries. Snapshot is already set. */
plan_list = pg_plan_queries(query_list, false);
/* Save the results. */
StoreQuery(stmt->name, query_list, plan_list, stmt->argtype_oids);
}
......@@ -92,17 +90,19 @@ void
ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
{
QueryHashEntry *entry;
List *l,
*query_list,
List *query_list,
*plan_list;
MemoryContext qcontext;
ParamListInfo paramLI = NULL;
EState *estate = NULL;
Portal portal;
/* Look it up in the hash table */
entry = FetchQuery(stmt->name);
query_list = entry->query_list;
plan_list = entry->plan_list;
qcontext = entry->context;
Assert(length(query_list) == length(plan_list));
......@@ -117,57 +117,53 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
paramLI = EvaluateParams(estate, stmt->params, entry->argtype_list);
}
/* Execute each query */
foreach(l, query_list)
{
Query *query = (Query *) lfirst(l);
Plan *plan = (Plan *) lfirst(plan_list);
bool is_last_query;
plan_list = lnext(plan_list);
is_last_query = (plan_list == NIL);
if (query->commandType == CMD_UTILITY)
ProcessUtility(query->utilityStmt, outputDest, NULL);
else
{
QueryDesc *qdesc;
if (log_executor_stats)
ResetUsage();
/*
* Create a new portal to run the query in
*/
portal = CreateNewPortal();
qdesc = CreateQueryDesc(query, plan, outputDest, NULL,
paramLI, false);
/*
* For EXECUTE INTO, make a copy of the stored query so that we can
* modify its destination (yech, but INTO has always been ugly).
* For regular EXECUTE we can just use the stored query where it sits,
* since the executor is read-only.
*/
if (stmt->into)
{
MemoryContext oldContext;
Query *query;
if (stmt->into)
{
if (qdesc->operation != CMD_SELECT)
elog(ERROR, "INTO clause specified for non-SELECT query");
oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
query->into = stmt->into;
qdesc->dest = None;
}
query_list = copyObject(query_list);
plan_list = copyObject(plan_list);
qcontext = PortalGetHeapMemory(portal);
ExecutorStart(qdesc);
if (length(query_list) != 1)
elog(ERROR, "INTO clause specified for non-SELECT query");
query = (Query *) lfirst(query_list);
if (query->commandType != CMD_SELECT)
elog(ERROR, "INTO clause specified for non-SELECT query");
query->into = copyObject(stmt->into);
ExecutorRun(qdesc, ForwardScanDirection, 0L);
MemoryContextSwitchTo(oldContext);
}
ExecutorEnd(qdesc);
PortalDefineQuery(portal,
NULL, /* XXX fixme: can we save query text? */
NULL, /* no command tag known either */
query_list,
plan_list,
qcontext);
FreeQueryDesc(qdesc);
/*
* Run the portal to completion.
*/
PortalStart(portal, paramLI);
if (log_executor_stats)
ShowUsage("EXECUTOR STATISTICS");
}
(void) PortalRun(portal, FETCH_ALL, outputDest, outputDest, NULL);
/*
* If we're processing multiple queries, we need to increment the
* command counter between them. For the last query, there's no
* need to do this, it's done automatically.
*/
if (!is_last_query)
CommandCounterIncrement();
}
PortalDrop(portal, false);
if (estate)
FreeExecutorState(estate);
......@@ -377,8 +373,11 @@ DeallocateQuery(DeallocateStmt *stmt)
/* Find the query's hash table entry */
entry = FetchQuery(stmt->name);
/* Flush the context holding the subsidiary data */
/* Drop any open portals that depend on this prepared statement */
Assert(MemoryContextIsValid(entry->context));
DropDependentPortals(entry->context);
/* Flush the context holding the subsidiary data */
MemoryContextDelete(entry->context);
/* Now we can remove the hash table entry */
......
......@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.251 2003/03/04 21:51:20 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.252 2003/05/02 20:54:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -189,11 +189,11 @@ vacuum(VacuumStmt *vacstmt)
/*
* Create special memory context for cross-transaction storage.
*
* Since it is a child of QueryContext, it will go away eventually even
* Since it is a child of PortalContext, it will go away eventually even
* if we suffer an error; there's no need for special abort cleanup
* logic.
*/
vac_context = AllocSetContextCreate(QueryContext,
vac_context = AllocSetContextCreate(PortalContext,
"Vacuum",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
......@@ -205,7 +205,7 @@ vacuum(VacuumStmt *vacstmt)
* lifetime.
*/
if (vacstmt->analyze && !vacstmt->vacuum)
anl_context = AllocSetContextCreate(QueryContext,
anl_context = AllocSetContextCreate(PortalContext,
"Analyze",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.128 2003/04/08 23:20:00 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.129 2003/05/02 20:54:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -377,7 +377,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
* XXX this is a horrid crock: since the pointer to the slot might live
* longer than the current evaluation context, we are forced to copy
* the tuple and slot into a long-lived context --- we use
* TransactionCommandContext which should be safe enough. This
* the econtext's per-query memory which should be safe enough. This
* represents a serious memory leak if many such tuples are processed
* in one command, however. We ought to redesign the representation
* of whole-tuple datums so that this is not necessary.
......@@ -391,7 +391,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
TupleTableSlot *tempSlot;
HeapTuple tup;
oldContext = MemoryContextSwitchTo(TransactionCommandContext);
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
tempSlot = MakeTupleTableSlot();
tup = heap_copytuple(heapTuple);
ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);
......
This diff is collapsed.
......@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.2 2003/04/29 03:21:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.3 2003/05/02 20:54:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -43,18 +43,18 @@ tstoreSetupReceiver(DestReceiver *self, int operation,
const char *portalname, TupleDesc typeinfo)
{
TStoreState *myState = (TStoreState *) self;
Portal portal;
if (operation != CMD_SELECT)
elog(ERROR, "Unexpected operation type: %d", operation);
/* Should only be called within a suitably-prepped portal */
if (CurrentPortal == NULL ||
CurrentPortal->holdStore == NULL)
elog(ERROR, "Tuplestore destination used in wrong context");
portal = GetPortalByName(portalname);
/* Debug check: make sure portal's result tuple desc is correct */
Assert(CurrentPortal->tupDesc != NULL);
Assert(equalTupleDescs(CurrentPortal->tupDesc, typeinfo));
if (portal == NULL)
elog(ERROR, "Specified portal does not exist: %s", portalname);
myState->tstore = portal->holdStore;
myState->cxt = portal->holdContext;
myState->tstore = CurrentPortal->holdStore;
myState->cxt = CurrentPortal->holdContext;
}
/*
......
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.248 2003/04/08 23:20:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.249 2003/05/02 20:54:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1476,6 +1476,7 @@ _copyQuery(Query *from)
COPY_SCALAR_FIELD(commandType);
COPY_SCALAR_FIELD(querySource);
COPY_SCALAR_FIELD(canSetTag);
COPY_NODE_FIELD(utilityStmt);
COPY_SCALAR_FIELD(resultRelation);
COPY_NODE_FIELD(into);
......
......@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.191 2003/04/08 23:20:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.192 2003/05/02 20:54:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -566,6 +566,7 @@ _equalQuery(Query *a, Query *b)
{
COMPARE_SCALAR_FIELD(commandType);
COMPARE_SCALAR_FIELD(querySource);
COMPARE_SCALAR_FIELD(canSetTag);
COMPARE_NODE_FIELD(utilityStmt);
COMPARE_SCALAR_FIELD(resultRelation);
COMPARE_NODE_FIELD(into);
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.203 2003/04/24 21:16:43 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.204 2003/05/02 20:54:34 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
......@@ -1177,6 +1177,7 @@ _outQuery(StringInfo str, Query *node)
WRITE_ENUM_FIELD(commandType, CmdType);
WRITE_ENUM_FIELD(querySource, QuerySource);
WRITE_BOOL_FIELD(canSetTag);
/*
* Hack to work around missing outfuncs routines for a lot of the
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.151 2003/04/08 23:20:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.152 2003/05/02 20:54:34 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
......@@ -195,6 +195,7 @@ _readQuery(void)
READ_ENUM_FIELD(commandType, CmdType);
READ_ENUM_FIELD(querySource, QuerySource);
READ_BOOL_FIELD(canSetTag);
READ_NODE_FIELD(utilityStmt);
READ_INT_FIELD(resultRelation);
READ_NODE_FIELD(into);
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.61 2003/01/20 18:54:49 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.62 2003/05/02 20:54:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -65,10 +65,10 @@ geqo_eval(Query *root, List *initial_rels, Gene *tour, int num_gene)
*
* Since geqo_eval() will be called many times, we can't afford to let
* all that memory go unreclaimed until end of statement. Note we
* make the temp context a child of TransactionCommandContext, so that
* make the temp context a child of the planner's normal context, so that
* it will be freed even if we abort via elog(ERROR).
*/
mycontext = AllocSetContextCreate(TransactionCommandContext,
mycontext = AllocSetContextCreate(CurrentMemoryContext,
"GEQO",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.268 2003/04/29 22:13:09 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.269 2003/05/02 20:54:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -237,13 +237,23 @@ do_parse_analyze(Node *parseTree, ParseState *pstate)
/*
* Make sure that only the original query is marked original. We have
* to do this explicitly since recursive calls of do_parse_analyze will
* have marked some of the added-on queries as "original".
* have marked some of the added-on queries as "original". Also mark
* only the original query as allowed to set the command-result tag.
*/
foreach(listscan, result)
{
Query *q = lfirst(listscan);
q->querySource = (q == query ? QSRC_ORIGINAL : QSRC_PARSER);
if (q == query)
{
q->querySource = QSRC_ORIGINAL;
q->canSetTag = true;
}
else
{
q->querySource = QSRC_PARSER;
q->canSetTag = false;
}
}
return result;
......@@ -399,6 +409,11 @@ transformStmt(ParseState *pstate, Node *parseTree,
result->utilityStmt = (Node *) parseTree;
break;
}
/* Mark as original query until we learn differently */
result->querySource = QSRC_ORIGINAL;
result->canSetTag = true;
return result;
}
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.119 2003/04/29 22:13:10 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.120 2003/05/02 20:54:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1016,6 +1016,7 @@ fireRules(Query *parsetree,
event_qual, rt_index, event);
rule_action->querySource = qsrc;
rule_action->canSetTag = false; /* might change later */
results = lappend(results, rule_action);
}
......@@ -1181,6 +1182,9 @@ QueryRewrite(Query *parsetree)
List *querylist;
List *results = NIL;
List *l;
CmdType origCmdType;
bool foundOriginalQuery;
Query *lastInstead;
/*
* Step 1
......@@ -1235,5 +1239,51 @@ QueryRewrite(Query *parsetree)
results = lappend(results, query);
}
/*
* Step 3
*
* Determine which, if any, of the resulting queries is supposed to set
* the command-result tag; and update the canSetTag fields accordingly.
*
* If the original query is still in the list, it sets the command tag.
* Otherwise, the last INSTEAD query of the same kind as the original
* is allowed to set the tag. (Note these rules can leave us with no
* query setting the tag. The tcop code has to cope with this by
* setting up a default tag based on the original un-rewritten query.)
*
* The Asserts verify that at most one query in the result list is marked
* canSetTag. If we aren't checking asserts, we can fall out of the loop
* as soon as we find the original query.
*/
origCmdType = parsetree->commandType;
foundOriginalQuery = false;
lastInstead = NULL;
foreach(l, results)
{
Query *query = (Query *) lfirst(l);
if (query->querySource == QSRC_ORIGINAL)
{
Assert(query->canSetTag);
Assert(!foundOriginalQuery);
foundOriginalQuery = true;
#ifndef USE_ASSERT_CHECKING
break;
#endif
}
else
{
Assert(!query->canSetTag);
if (query->commandType == origCmdType &&
(query->querySource == QSRC_INSTEAD_RULE ||
query->querySource == QSRC_QUAL_INSTEAD_RULE))
lastInstead = query;
}
}
if (!foundOriginalQuery && lastInstead != NULL)
lastInstead->canSetTag = true;
return results;
}
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.59 2003/04/22 00:08:07 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.60 2003/05/02 20:54:35 tgl Exp $
*
* NOTES
* This cruft is the server side of PQfn.
......@@ -255,7 +255,7 @@ fetch_fp_info(Oid func_id, struct fp_info * fip)
*
* Note: palloc()s done here and in the called function do not need to be
* cleaned up explicitly. We are called from PostgresMain() in the
* QueryContext memory context, which will be automatically reset when
* MessageContext memory context, which will be automatically reset when
* control returns to PostgresMain.
*/
int
......
This diff is collapsed.
This diff is collapsed.
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.197 2003/03/20 18:52:48 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.198 2003/05/02 20:54:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1027,3 +1027,386 @@ ProcessUtility(Node *parsetree,
break;
}
}
/*
* CreateCommandTag
* utility to get a string representation of the
* command operation, given a raw (un-analyzed) parsetree.
*
* This must handle all raw command types, but since the vast majority
* of 'em are utility commands, it seems sensible to keep it here.
*
* NB: all result strings must be shorter than COMPLETION_TAG_BUFSIZE.
* Also, the result must point at a true constant (permanent storage).
*/
const char *
CreateCommandTag(Node *parsetree)
{
const char *tag;
switch (nodeTag(parsetree))
{
case T_InsertStmt:
tag = "INSERT";
break;
case T_DeleteStmt:
tag = "DELETE";
break;
case T_UpdateStmt:
tag = "UPDATE";
break;
case T_SelectStmt:
tag = "SELECT";
break;
case T_TransactionStmt:
{
TransactionStmt *stmt = (TransactionStmt *) parsetree;
switch (stmt->kind)
{
case TRANS_STMT_BEGIN:
tag = "BEGIN";
break;
case TRANS_STMT_START:
tag = "START TRANSACTION";
break;
case TRANS_STMT_COMMIT:
tag = "COMMIT";
break;
case TRANS_STMT_ROLLBACK:
tag = "ROLLBACK";
break;
default:
tag = "???";
break;
}
}
break;
case T_DeclareCursorStmt:
tag = "DECLARE CURSOR";
break;
case T_ClosePortalStmt:
tag = "CLOSE CURSOR";
break;
case T_FetchStmt:
{
FetchStmt *stmt = (FetchStmt *) parsetree;
tag = (stmt->ismove) ? "MOVE" : "FETCH";
}
break;
case T_CreateDomainStmt:
tag = "CREATE DOMAIN";
break;
case T_CreateSchemaStmt:
tag = "CREATE SCHEMA";
break;
case T_CreateStmt:
tag = "CREATE TABLE";
break;
case T_DropStmt:
switch (((DropStmt *) parsetree)->removeType)
{
case DROP_TABLE:
tag = "DROP TABLE";
break;
case DROP_SEQUENCE:
tag = "DROP SEQUENCE";
break;
case DROP_VIEW:
tag = "DROP VIEW";
break;
case DROP_INDEX:
tag = "DROP INDEX";
break;
case DROP_TYPE:
tag = "DROP TYPE";
break;
case DROP_DOMAIN:
tag = "DROP DOMAIN";
break;
case DROP_CONVERSION:
tag = "DROP CONVERSION";
break;
case DROP_SCHEMA:
tag = "DROP SCHEMA";
break;
default:
tag = "???";
}
break;
case T_TruncateStmt:
tag = "TRUNCATE TABLE";
break;
case T_CommentStmt:
tag = "COMMENT";
break;
case T_CopyStmt:
tag = "COPY";
break;
case T_RenameStmt:
if (((RenameStmt *) parsetree)->renameType == RENAME_TRIGGER)
tag = "ALTER TRIGGER";
else
tag = "ALTER TABLE";
break;
case T_AlterTableStmt:
tag = "ALTER TABLE";
break;
case T_AlterDomainStmt:
tag = "ALTER DOMAIN";
break;
case T_GrantStmt:
{
GrantStmt *stmt = (GrantStmt *) parsetree;
tag = (stmt->is_grant) ? "GRANT" : "REVOKE";
}
break;
case T_DefineStmt:
switch (((DefineStmt *) parsetree)->kind)
{
case DEFINE_STMT_AGGREGATE:
tag = "CREATE AGGREGATE";
break;
case DEFINE_STMT_OPERATOR:
tag = "CREATE OPERATOR";
break;
case DEFINE_STMT_TYPE:
tag = "CREATE TYPE";
break;
default:
tag = "???";
}
break;
case T_CompositeTypeStmt:
tag = "CREATE TYPE";
break;
case T_ViewStmt:
tag = "CREATE VIEW";
break;
case T_CreateFunctionStmt:
tag = "CREATE FUNCTION";
break;
case T_IndexStmt:
tag = "CREATE INDEX";
break;
case T_RuleStmt:
tag = "CREATE RULE";
break;
case T_CreateSeqStmt:
tag = "CREATE SEQUENCE";
break;
case T_AlterSeqStmt:
tag = "ALTER SEQUENCE";
break;
case T_RemoveAggrStmt:
tag = "DROP AGGREGATE";
break;
case T_RemoveFuncStmt:
tag = "DROP FUNCTION";
break;
case T_RemoveOperStmt:
tag = "DROP OPERATOR";
break;
case T_CreatedbStmt:
tag = "CREATE DATABASE";
break;
case T_AlterDatabaseSetStmt:
tag = "ALTER DATABASE";
break;
case T_DropdbStmt:
tag = "DROP DATABASE";
break;
case T_NotifyStmt:
tag = "NOTIFY";
break;
case T_ListenStmt:
tag = "LISTEN";
break;
case T_UnlistenStmt:
tag = "UNLISTEN";
break;
case T_LoadStmt:
tag = "LOAD";
break;
case T_ClusterStmt:
tag = "CLUSTER";
break;
case T_VacuumStmt:
if (((VacuumStmt *) parsetree)->vacuum)
tag = "VACUUM";
else
tag = "ANALYZE";
break;
case T_ExplainStmt:
tag = "EXPLAIN";
break;
case T_VariableSetStmt:
tag = "SET";
break;
case T_VariableShowStmt:
tag = "SHOW";
break;
case T_VariableResetStmt:
tag = "RESET";
break;
case T_CreateTrigStmt:
tag = "CREATE TRIGGER";
break;
case T_DropPropertyStmt:
switch (((DropPropertyStmt *) parsetree)->removeType)
{
case DROP_TRIGGER:
tag = "DROP TRIGGER";
break;
case DROP_RULE:
tag = "DROP RULE";
break;
default:
tag = "???";
}
break;
case T_CreatePLangStmt:
tag = "CREATE LANGUAGE";
break;
case T_DropPLangStmt:
tag = "DROP LANGUAGE";
break;
case T_CreateUserStmt:
tag = "CREATE USER";
break;
case T_AlterUserStmt:
tag = "ALTER USER";
break;
case T_AlterUserSetStmt:
tag = "ALTER USER";
break;
case T_DropUserStmt:
tag = "DROP USER";
break;
case T_LockStmt:
tag = "LOCK TABLE";
break;
case T_ConstraintsSetStmt:
tag = "SET CONSTRAINTS";
break;
case T_CreateGroupStmt:
tag = "CREATE GROUP";
break;
case T_AlterGroupStmt:
tag = "ALTER GROUP";
break;
case T_DropGroupStmt:
tag = "DROP GROUP";
break;
case T_CheckPointStmt:
tag = "CHECKPOINT";
break;
case T_ReindexStmt:
tag = "REINDEX";
break;
case T_CreateConversionStmt:
tag = "CREATE CONVERSION";
break;
case T_CreateCastStmt:
tag = "CREATE CAST";
break;
case T_DropCastStmt:
tag = "DROP CAST";
break;
case T_CreateOpClassStmt:
tag = "CREATE OPERATOR CLASS";
break;
case T_RemoveOpClassStmt:
tag = "DROP OPERATOR CLASS";
break;
case T_PrepareStmt:
tag = "PREPARE";
break;
case T_ExecuteStmt:
tag = "EXECUTE";
break;
case T_DeallocateStmt:
tag = "DEALLOCATE";
break;
default:
elog(LOG, "CreateCommandTag: unknown parse node type %d",
nodeTag(parsetree));
tag = "???";
break;
}
return tag;
}
......@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.39 2003/03/27 16:51:29 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.40 2003/05/02 20:54:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -43,9 +43,11 @@ MemoryContext TopMemoryContext = NULL;
MemoryContext ErrorContext = NULL;
MemoryContext PostmasterContext = NULL;
MemoryContext CacheMemoryContext = NULL;
MemoryContext QueryContext = NULL;
MemoryContext MessageContext = NULL;
MemoryContext TopTransactionContext = NULL;
MemoryContext TransactionCommandContext = NULL;
/* These two are transient links to contexts owned by other objects: */
MemoryContext QueryContext = NULL;
MemoryContext PortalContext = NULL;
/*****************************************************************************
......
This diff is collapsed.
......@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catversion.h,v 1.184 2003/04/08 23:20:02 tgl Exp $
* $Id: catversion.h,v 1.185 2003/05/02 20:54:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200304071
#define CATALOG_VERSION_NO 200305011
#endif
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: portalcmds.h,v 1.7 2003/04/29 03:21:30 tgl Exp $
* $Id: portalcmds.h,v 1.8 2003/05/02 20:54:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -22,13 +22,10 @@ extern void PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest);
extern void PerformPortalFetch(FetchStmt *stmt, CommandDest dest,
char *completionTag);
extern long DoPortalFetch(Portal portal,
FetchDirection fdirection,
long count,
CommandDest dest);
extern void PerformPortalClose(char *name);
extern void PortalCleanup(Portal portal, bool isError);
extern void PersistHoldablePortal(Portal portal);
#endif /* PORTALCMDS_H */
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: spi_priv.h,v 1.13 2002/10/14 23:49:20 tgl Exp $
* $Id: spi_priv.h,v 1.14 2003/05/02 20:54:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -36,8 +36,6 @@ typedef struct
/* Argument types, if a prepared plan */
int nargs;
Oid *argtypes;
/* Command type of last original parsetree */
CmdType origCmdType;
} _SPI_plan;
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.236 2003/03/27 16:51:29 momjian Exp $
* $Id: parsenodes.h,v 1.237 2003/05/02 20:54:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -47,6 +47,8 @@ typedef struct Query
QuerySource querySource; /* where did I come from? */
bool canSetTag; /* do I set the command result tag? */
Node *utilityStmt; /* non-null if this is a non-optimizable
* statement */
......
......@@ -7,17 +7,32 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pquery.h,v 1.24 2003/03/10 03:53:52 tgl Exp $
* $Id: pquery.h,v 1.25 2003/05/02 20:54:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PQUERY_H
#define PQUERY_H
#include "executor/execdesc.h"
#include "utils/portal.h"
extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest,
char *completionTag);
extern void ProcessQuery(Query *parsetree,
Plan *plan,
ParamListInfo params,
const char *portalName,
CommandDest dest,
char *completionTag);
extern void PortalStart(Portal portal, ParamListInfo params);
extern bool PortalRun(Portal portal, long count,
CommandDest dest, CommandDest altdest,
char *completionTag);
extern long PortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
CommandDest dest);
#endif /* PQUERY_H */
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: tcopprot.h,v 1.55 2003/04/29 22:13:11 tgl Exp $
* $Id: tcopprot.h,v 1.56 2003/05/02 20:54:36 tgl Exp $
*
* OLD COMMENTS
* This file was created so that other c files could get the two
......@@ -41,6 +41,7 @@ extern List *pg_analyze_and_rewrite(Node *parsetree,
extern List *pg_parse_and_rewrite(const char *query_string,
Oid *paramTypes, int numParams);
extern Plan *pg_plan_query(Query *querytree);
extern List *pg_plan_queries(List *querytrees, bool needSnapshot);
#endif /* BOOTSTRAP_INCLUDE */
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: utility.h,v 1.16 2002/09/04 20:31:45 momjian Exp $
* $Id: utility.h,v 1.17 2003/05/02 20:54:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -19,4 +19,6 @@
extern void ProcessUtility(Node *parsetree, CommandDest dest,
char *completionTag);
extern const char *CreateCommandTag(Node *parsetree);
#endif /* UTILITY_H */
......@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: memutils.h,v 1.50 2002/12/16 16:22:46 tgl Exp $
* $Id: memutils.h,v 1.51 2003/05/02 20:54:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -68,9 +68,11 @@ extern DLLIMPORT MemoryContext TopMemoryContext;
extern DLLIMPORT MemoryContext ErrorContext;
extern DLLIMPORT MemoryContext PostmasterContext;
extern DLLIMPORT MemoryContext CacheMemoryContext;
extern DLLIMPORT MemoryContext QueryContext;
extern DLLIMPORT MemoryContext MessageContext;
extern DLLIMPORT MemoryContext TopTransactionContext;
extern DLLIMPORT MemoryContext TransactionCommandContext;
/* These two are transient links to contexts owned by other objects: */
extern DLLIMPORT MemoryContext QueryContext;
extern DLLIMPORT MemoryContext PortalContext;
/*
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment