Commit b9527e98 authored by Tom Lane's avatar Tom Lane

First phase of plan-invalidation project: create a plan cache management

module and teach PREPARE and protocol-level prepared statements to use it.
In service of this, rearrange utility-statement processing so that parse
analysis does not assume table schemas can't change before execution for
utility statements (necessary because we don't attempt to re-acquire locks
for utility statements when reusing a stored plan).  This requires some
refactoring of the ProcessUtility API, but it ends up cleaner anyway,
for instance we can get rid of the QueryContext global.

Still to do: fix up SPI and related code to use the plan cache; I'm tempted to
try to make SQL functions use it too.  Also, there are at least some aspects
of system state that we want to ensure remain the same during a replan as in
the original processing; search_path certainly ought to behave that way for
instance, and perhaps there are others.
parent f84308f1
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.235 2007/03/12 22:09:27 petere Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.236 2007/03/13 00:33:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2504,12 +2504,13 @@ AbortCurrentTransaction(void) ...@@ -2504,12 +2504,13 @@ AbortCurrentTransaction(void)
* could issue more commands and possibly cause a failure after the statement * could issue more commands and possibly cause a failure after the statement
* completes). Subtransactions are verboten too. * completes). Subtransactions are verboten too.
* *
* stmtNode: pointer to parameter block for statement; this is used in * isTopLevel: passed down from ProcessUtility to determine whether we are
* a very klugy way to determine whether we are inside a function. * inside a function. (We will always fail if this is false, but it's
* stmtType: statement type name for error messages. * convenient to centralize the check here instead of making callers do it.)
* stmtType: statement type name, for error messages.
*/ */
void void
PreventTransactionChain(void *stmtNode, const char *stmtType) PreventTransactionChain(bool isTopLevel, const char *stmtType)
{ {
/* /*
* xact block already started? * xact block already started?
...@@ -2532,11 +2533,9 @@ PreventTransactionChain(void *stmtNode, const char *stmtType) ...@@ -2532,11 +2533,9 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
stmtType))); stmtType)));
/* /*
* Are we inside a function call? If the statement's parameter block was * inside a function call?
* allocated in QueryContext, assume it is an interactive command.
* Otherwise assume it is coming from a function.
*/ */
if (!MemoryContextContains(QueryContext, stmtNode)) if (!isTopLevel)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
/* translator: %s represents an SQL statement name */ /* translator: %s represents an SQL statement name */
...@@ -2562,12 +2561,12 @@ PreventTransactionChain(void *stmtNode, const char *stmtType) ...@@ -2562,12 +2561,12 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
* use of the current statement's results. Likewise subtransactions. * use of the current statement's results. Likewise subtransactions.
* Thus this is an inverse for PreventTransactionChain. * Thus this is an inverse for PreventTransactionChain.
* *
* stmtNode: pointer to parameter block for statement; this is used in * isTopLevel: passed down from ProcessUtility to determine whether we are
* a very klugy way to determine whether we are inside a function. * inside a function.
* stmtType: statement type name for error messages. * stmtType: statement type name, for error messages.
*/ */
void void
RequireTransactionChain(void *stmtNode, const char *stmtType) RequireTransactionChain(bool isTopLevel, const char *stmtType)
{ {
/* /*
* xact block already started? * xact block already started?
...@@ -2582,12 +2581,11 @@ RequireTransactionChain(void *stmtNode, const char *stmtType) ...@@ -2582,12 +2581,11 @@ RequireTransactionChain(void *stmtNode, const char *stmtType)
return; return;
/* /*
* Are we inside a function call? If the statement's parameter block was * inside a function call?
* allocated in QueryContext, assume it is an interactive command.
* Otherwise assume it is coming from a function.
*/ */
if (!MemoryContextContains(QueryContext, stmtNode)) if (!isTopLevel)
return; return;
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION), (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
/* translator: %s represents an SQL statement name */ /* translator: %s represents an SQL statement name */
...@@ -2602,11 +2600,11 @@ RequireTransactionChain(void *stmtNode, const char *stmtType) ...@@ -2602,11 +2600,11 @@ RequireTransactionChain(void *stmtNode, const char *stmtType)
* a transaction block than when running as single commands. ANALYZE is * a transaction block than when running as single commands. ANALYZE is
* currently the only example. * currently the only example.
* *
* stmtNode: pointer to parameter block for statement; this is used in * isTopLevel: passed down from ProcessUtility to determine whether we are
* a very klugy way to determine whether we are inside a function. * inside a function.
*/ */
bool bool
IsInTransactionChain(void *stmtNode) IsInTransactionChain(bool isTopLevel)
{ {
/* /*
* Return true on same conditions that would make PreventTransactionChain * Return true on same conditions that would make PreventTransactionChain
...@@ -2618,7 +2616,7 @@ IsInTransactionChain(void *stmtNode) ...@@ -2618,7 +2616,7 @@ IsInTransactionChain(void *stmtNode)
if (IsSubTransaction()) if (IsSubTransaction())
return true; return true;
if (!MemoryContextContains(QueryContext, stmtNode)) if (!isTopLevel)
return true; return true;
if (CurrentTransactionState->blockState != TBLOCK_DEFAULT && if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.87 2007/03/07 13:35:02 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.88 2007/03/13 00:33:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -252,7 +252,7 @@ Boot_DeclareIndexStmt: ...@@ -252,7 +252,7 @@ Boot_DeclareIndexStmt:
LexIDStr($8), LexIDStr($8),
NULL, NULL,
$10, $10,
NULL, NIL, NIL, NULL, NIL,
false, false, false, false, false, false,
false, false, true, false, false); false, false, true, false, false);
do_end(); do_end();
...@@ -270,7 +270,7 @@ Boot_DeclareUniqueIndexStmt: ...@@ -270,7 +270,7 @@ Boot_DeclareUniqueIndexStmt:
LexIDStr($9), LexIDStr($9),
NULL, NULL,
$11, $11,
NULL, NIL, NIL, NULL, NIL,
true, false, false, true, false, false,
false, false, true, false, false); false, false, true, false, false);
do_end(); do_end();
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.156 2007/02/01 19:10:25 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.157 2007/03/13 00:33:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -82,7 +82,7 @@ static List *get_tables_to_cluster(MemoryContext cluster_context); ...@@ -82,7 +82,7 @@ static List *get_tables_to_cluster(MemoryContext cluster_context);
*--------------------------------------------------------------------------- *---------------------------------------------------------------------------
*/ */
void void
cluster(ClusterStmt *stmt) cluster(ClusterStmt *stmt, bool isTopLevel)
{ {
if (stmt->relation != NULL) if (stmt->relation != NULL)
{ {
...@@ -173,7 +173,7 @@ cluster(ClusterStmt *stmt) ...@@ -173,7 +173,7 @@ cluster(ClusterStmt *stmt)
* We cannot run this form of CLUSTER inside a user transaction block; * We cannot run this form of CLUSTER inside a user transaction block;
* we'd be holding locks way too long. * we'd be holding locks way too long.
*/ */
PreventTransactionChain((void *) stmt, "CLUSTER"); PreventTransactionChain(isTopLevel, "CLUSTER");
/* /*
* Create special memory context for cross-transaction storage. * Create special memory context for cross-transaction storage.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.277 2007/03/03 19:32:54 neilc Exp $ * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.278 2007/03/13 00:33:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -713,7 +713,7 @@ CopyLoadRawBuf(CopyState cstate) ...@@ -713,7 +713,7 @@ CopyLoadRawBuf(CopyState cstate)
* the table. * the table.
*/ */
uint64 uint64
DoCopy(const CopyStmt *stmt) DoCopy(const CopyStmt *stmt, const char *queryString)
{ {
CopyState cstate; CopyState cstate;
bool is_from = stmt->is_from; bool is_from = stmt->is_from;
...@@ -982,13 +982,11 @@ DoCopy(const CopyStmt *stmt) ...@@ -982,13 +982,11 @@ DoCopy(const CopyStmt *stmt)
} }
else else
{ {
Query *query = stmt->query;
List *rewritten; List *rewritten;
Query *query;
PlannedStmt *plan; PlannedStmt *plan;
DestReceiver *dest; DestReceiver *dest;
Assert(query);
Assert(query->commandType == CMD_SELECT);
Assert(!is_from); Assert(!is_from);
cstate->rel = NULL; cstate->rel = NULL;
...@@ -998,33 +996,18 @@ DoCopy(const CopyStmt *stmt) ...@@ -998,33 +996,18 @@ DoCopy(const CopyStmt *stmt)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("COPY (SELECT) WITH OIDS is not supported"))); errmsg("COPY (SELECT) WITH OIDS is not supported")));
/* Query mustn't use INTO, either */
if (query->into)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("COPY (SELECT INTO) is not supported")));
/* /*
* The query has already been through parse analysis, but not * Run parse analysis and rewrite. Note this also acquires sufficient
* rewriting or planning. Do that now. * locks on the source table(s).
* *
* Because the planner is not cool about not scribbling on its input, * Because the parser and planner tend to scribble on their input, we
* we make a preliminary copy of the source querytree. This prevents * make a preliminary copy of the source querytree. This prevents
* problems in the case that the COPY is in a portal or plpgsql * problems in the case that the COPY is in a portal or plpgsql
* function and is executed repeatedly. (See also the same hack in * function and is executed repeatedly. (See also the same hack in
* EXPLAIN, DECLARE CURSOR and PREPARE.) XXX the planner really * DECLARE CURSOR and PREPARE.) XXX FIXME someday.
* shouldn't modify its input ... FIXME someday.
*/ */
query = copyObject(query); rewritten = pg_analyze_and_rewrite((Node *) copyObject(stmt->query),
queryString, NULL, 0);
/*
* Must acquire locks in case we didn't come fresh from the parser.
* XXX this also scribbles on query, another reason for copyObject
*/
AcquireRewriteLocks(query);
/* Rewrite through rule system */
rewritten = QueryRewrite(query);
/* We don't expect more or less than one result query */ /* We don't expect more or less than one result query */
if (list_length(rewritten) != 1) if (list_length(rewritten) != 1)
...@@ -1033,6 +1016,12 @@ DoCopy(const CopyStmt *stmt) ...@@ -1033,6 +1016,12 @@ DoCopy(const CopyStmt *stmt)
query = (Query *) linitial(rewritten); query = (Query *) linitial(rewritten);
Assert(query->commandType == CMD_SELECT); Assert(query->commandType == CMD_SELECT);
/* Query mustn't use INTO, either */
if (query->into)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("COPY (SELECT INTO) is not supported")));
/* plan the query */ /* plan the query */
plan = planner(query, false, 0, NULL); plan = planner(query, false, 0, NULL);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.192 2007/02/09 16:12:18 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.193 2007/03/13 00:33:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -97,9 +97,6 @@ createdb(const CreatedbStmt *stmt) ...@@ -97,9 +97,6 @@ createdb(const CreatedbStmt *stmt)
int encoding = -1; int encoding = -1;
int dbconnlimit = -1; int dbconnlimit = -1;
/* don't call this in a transaction block */
PreventTransactionChain((void *) stmt, "CREATE DATABASE");
/* Extract options from the statement node tree */ /* Extract options from the statement node tree */
foreach(option, stmt->options) foreach(option, stmt->options)
{ {
...@@ -545,8 +542,6 @@ dropdb(const char *dbname, bool missing_ok) ...@@ -545,8 +542,6 @@ dropdb(const char *dbname, bool missing_ok)
Relation pgdbrel; Relation pgdbrel;
HeapTuple tup; HeapTuple tup;
PreventTransactionChain((void *) dbname, "DROP DATABASE");
AssertArg(dbname); AssertArg(dbname);
if (strcmp(dbname, get_database_name(MyDatabaseId)) == 0) if (strcmp(dbname, get_database_name(MyDatabaseId)) == 0)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.159 2007/02/23 21:59:44 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.160 2007/03/13 00:33:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "optimizer/var.h" #include "optimizer/var.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h" #include "rewrite/rewriteHandler.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
...@@ -41,8 +42,9 @@ typedef struct ExplainState ...@@ -41,8 +42,9 @@ typedef struct ExplainState
List *rtable; /* range table */ List *rtable; /* range table */
} ExplainState; } ExplainState;
static void ExplainOneQuery(Query *query, ExplainStmt *stmt, static void ExplainOneQuery(Query *query, bool isCursor, int cursorOptions,
ParamListInfo params, TupOutputState *tstate); ExplainStmt *stmt, const char *queryString,
ParamListInfo params, TupOutputState *tstate);
static double elapsed_time(instr_time *starttime); static double elapsed_time(instr_time *starttime);
static void explain_outNode(StringInfo str, static void explain_outNode(StringInfo str,
Plan *plan, PlanState *planstate, Plan *plan, PlanState *planstate,
...@@ -62,62 +64,49 @@ static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, ...@@ -62,62 +64,49 @@ static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
* execute an EXPLAIN command * execute an EXPLAIN command
*/ */
void void
ExplainQuery(ExplainStmt *stmt, ParamListInfo params, DestReceiver *dest) ExplainQuery(ExplainStmt *stmt, const char *queryString,
ParamListInfo params, DestReceiver *dest)
{ {
Query *query = stmt->query; Oid *param_types;
int num_params;
TupOutputState *tstate; TupOutputState *tstate;
List *rewritten; List *rewritten;
ListCell *l; ListCell *l;
/* Convert parameter type data to the form parser wants */
getParamListTypes(params, &param_types, &num_params);
/* /*
* Because the planner is not cool about not scribbling on its input, we * Run parse analysis and rewrite. Note this also acquires sufficient
* locks on the source table(s).
*
* Because the parser and planner tend to scribble on their input, we
* make a preliminary copy of the source querytree. This prevents * make a preliminary copy of the source querytree. This prevents
* problems in the case that the EXPLAIN is in a portal or plpgsql * problems in the case that the EXPLAIN is in a portal or plpgsql
* function and is executed repeatedly. (See also the same hack in * function and is executed repeatedly. (See also the same hack in
* DECLARE CURSOR and PREPARE.) XXX the planner really shouldn't modify * DECLARE CURSOR and PREPARE.) XXX FIXME someday.
* its input ... FIXME someday.
*/ */
query = copyObject(query); rewritten = pg_analyze_and_rewrite((Node *) copyObject(stmt->query),
queryString, param_types, num_params);
/* prepare for projection of tuples */ /* prepare for projection of tuples */
tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt)); tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
if (query->commandType == CMD_UTILITY) if (rewritten == NIL)
{ {
/* Rewriter will not cope with utility statements */ /* In the case of an INSTEAD NOTHING, tell at least that */
if (query->utilityStmt && IsA(query->utilityStmt, DeclareCursorStmt)) do_text_output_oneline(tstate, "Query rewrites to nothing");
ExplainOneQuery(query, stmt, params, tstate);
else if (query->utilityStmt && IsA(query->utilityStmt, ExecuteStmt))
ExplainExecuteQuery(stmt, params, tstate);
else
do_text_output_oneline(tstate, "Utility statements have no plan structure");
} }
else else
{ {
/* /* Explain every plan */
* Must acquire locks in case we didn't come fresh from the parser. foreach(l, rewritten)
* XXX this also scribbles on query, another reason for copyObject
*/
AcquireRewriteLocks(query);
/* Rewrite through rule system */
rewritten = QueryRewrite(query);
if (rewritten == NIL)
{
/* In the case of an INSTEAD NOTHING, tell at least that */
do_text_output_oneline(tstate, "Query rewrites to nothing");
}
else
{ {
/* Explain every plan */ ExplainOneQuery((Query *) lfirst(l), false, 0,
foreach(l, rewritten) stmt, queryString, params, tstate);
{ /* put a blank line between plans */
ExplainOneQuery(lfirst(l), stmt, params, tstate); if (lnext(l) != NULL)
/* put a blank line between plans */ do_text_output_oneline(tstate, "");
if (lnext(l) != NULL)
do_text_output_oneline(tstate, "");
}
} }
} }
...@@ -142,51 +131,22 @@ ExplainResultDesc(ExplainStmt *stmt) ...@@ -142,51 +131,22 @@ ExplainResultDesc(ExplainStmt *stmt)
/* /*
* ExplainOneQuery - * ExplainOneQuery -
* print out the execution plan for one query * print out the execution plan for one Query
*/ */
static void static void
ExplainOneQuery(Query *query, ExplainStmt *stmt, ParamListInfo params, ExplainOneQuery(Query *query, bool isCursor, int cursorOptions,
TupOutputState *tstate) ExplainStmt *stmt, const char *queryString,
ParamListInfo params, TupOutputState *tstate)
{ {
PlannedStmt *plan; PlannedStmt *plan;
QueryDesc *queryDesc; QueryDesc *queryDesc;
bool isCursor = false;
int cursorOptions = 0;
/* planner will not cope with utility statements */ /* planner will not cope with utility statements */
if (query->commandType == CMD_UTILITY) if (query->commandType == CMD_UTILITY)
{ {
if (query->utilityStmt && IsA(query->utilityStmt, DeclareCursorStmt)) ExplainOneUtility(query->utilityStmt, stmt,
{ queryString, params, tstate);
DeclareCursorStmt *dcstmt; return;
List *rewritten;
dcstmt = (DeclareCursorStmt *) query->utilityStmt;
query = (Query *) dcstmt->query;
isCursor = true;
cursorOptions = dcstmt->options;
/* Still need to rewrite cursor command */
Assert(query->commandType == CMD_SELECT);
/* get locks (we assume ExplainQuery already copied tree) */
AcquireRewriteLocks(query);
rewritten = QueryRewrite(query);
if (list_length(rewritten) != 1)
elog(ERROR, "unexpected rewrite result");
query = (Query *) linitial(rewritten);
Assert(query->commandType == CMD_SELECT);
/* do not actually execute the underlying query! */
stmt->analyze = false;
}
else if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
{
do_text_output_oneline(tstate, "NOTIFY");
return;
}
else
{
do_text_output_oneline(tstate, "UTILITY");
return;
}
} }
/* plan the query */ /* plan the query */
...@@ -210,6 +170,78 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, ParamListInfo params, ...@@ -210,6 +170,78 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, ParamListInfo params,
ExplainOnePlan(queryDesc, stmt, tstate); ExplainOnePlan(queryDesc, stmt, tstate);
} }
/*
* ExplainOneUtility -
* print out the execution plan for one utility statement
* (In general, utility statements don't have plans, but there are some
* we treat as special cases)
*
* This is exported because it's called back from prepare.c in the
* EXPLAIN EXECUTE case
*/
void
ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
const char *queryString, ParamListInfo params,
TupOutputState *tstate)
{
if (utilityStmt == NULL)
return;
if (IsA(utilityStmt, DeclareCursorStmt))
{
DeclareCursorStmt *dcstmt = (DeclareCursorStmt *) utilityStmt;
Oid *param_types;
int num_params;
Query *query;
List *rewritten;
ExplainStmt newstmt;
/* Convert parameter type data to the form parser wants */
getParamListTypes(params, &param_types, &num_params);
/*
* Run parse analysis and rewrite. Note this also acquires sufficient
* locks on the source table(s).
*
* Because the parser and planner tend to scribble on their input, we
* make a preliminary copy of the source querytree. This prevents
* problems in the case that the DECLARE CURSOR is in a portal or
* plpgsql function and is executed repeatedly. (See also the same
* hack in COPY and PREPARE.) XXX FIXME someday.
*/
rewritten = pg_analyze_and_rewrite((Node *) copyObject(dcstmt->query),
queryString,
param_types, num_params);
/* We don't expect more or less than one result query */
if (list_length(rewritten) != 1 || !IsA(linitial(rewritten), Query))
elog(ERROR, "unexpected rewrite result");
query = (Query *) linitial(rewritten);
if (query->commandType != CMD_SELECT)
elog(ERROR, "unexpected rewrite result");
/* But we must explicitly disallow DECLARE CURSOR ... SELECT INTO */
if (query->into)
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
errmsg("DECLARE CURSOR cannot specify INTO")));
/* do not actually execute the underlying query! */
memcpy(&newstmt, stmt, sizeof(ExplainStmt));
newstmt.analyze = false;
ExplainOneQuery(query, true, dcstmt->options, &newstmt,
queryString, params, tstate);
}
else if (IsA(utilityStmt, ExecuteStmt))
ExplainExecuteQuery((ExecuteStmt *) utilityStmt, stmt,
queryString, params, tstate);
else if (IsA(utilityStmt, NotifyStmt))
do_text_output_oneline(tstate, "NOTIFY");
else
do_text_output_oneline(tstate,
"Utility statements have no plan structure");
}
/* /*
* ExplainOnePlan - * ExplainOnePlan -
* given a planned query, execute it if needed, and then print * given a planned query, execute it if needed, and then print
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.156 2007/03/06 02:06:12 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.157 2007/03/13 00:33:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -77,7 +77,6 @@ static bool relationHasPrimaryKey(Relation rel); ...@@ -77,7 +77,6 @@ static bool relationHasPrimaryKey(Relation rel);
* 'attributeList': a list of IndexElem specifying columns and expressions * 'attributeList': a list of IndexElem specifying columns and expressions
* to index on. * to index on.
* 'predicate': the partial-index condition, or NULL if none. * 'predicate': the partial-index condition, or NULL if none.
* 'rangetable': needed to interpret the predicate.
* 'options': reloptions from WITH (in list-of-DefElem form). * 'options': reloptions from WITH (in list-of-DefElem form).
* 'unique': make the index enforce uniqueness. * 'unique': make the index enforce uniqueness.
* 'primary': mark the index as a primary key in the catalogs. * 'primary': mark the index as a primary key in the catalogs.
...@@ -99,7 +98,6 @@ DefineIndex(RangeVar *heapRelation, ...@@ -99,7 +98,6 @@ DefineIndex(RangeVar *heapRelation,
char *tableSpaceName, char *tableSpaceName,
List *attributeList, List *attributeList,
Expr *predicate, Expr *predicate,
List *rangetable,
List *options, List *options,
bool unique, bool unique,
bool primary, bool primary,
...@@ -300,18 +298,6 @@ DefineIndex(RangeVar *heapRelation, ...@@ -300,18 +298,6 @@ DefineIndex(RangeVar *heapRelation,
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
/*
* If a range table was created then check that only the base rel is
* mentioned.
*/
if (rangetable != NIL)
{
if (list_length(rangetable) != 1 || getrelid(1, rangetable) != relationId)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("index expressions and predicates can refer only to the table being indexed")));
}
/* /*
* Validate predicate, if given * Validate predicate, if given
*/ */
...@@ -1218,6 +1204,7 @@ ReindexTable(RangeVar *relation) ...@@ -1218,6 +1204,7 @@ ReindexTable(RangeVar *relation)
* *
* To reduce the probability of deadlocks, each table is reindexed in a * To reduce the probability of deadlocks, each table is reindexed in a
* separate transaction, so we can release the lock on it right away. * separate transaction, so we can release the lock on it right away.
* That means this must not be called within a user transaction block!
*/ */
void void
ReindexDatabase(const char *databaseName, bool do_system, bool do_user) ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
...@@ -1241,13 +1228,6 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) ...@@ -1241,13 +1228,6 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
databaseName); databaseName);
/*
* We cannot run inside a user transaction block; if we were inside a
* transaction, then our commit- and start-transaction-command calls would
* not have the intended effect!
*/
PreventTransactionChain((void *) databaseName, "REINDEX DATABASE");
/* /*
* Create a memory context that will survive forced transaction commits we * Create a memory context that will survive forced transaction commits we
* do below. Since it is a child of PortalContext, it will go away * do below. Since it is a child of PortalContext, it will go away
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.61 2007/02/20 17:32:14 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.62 2007/03/13 00:33:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -38,8 +38,11 @@ ...@@ -38,8 +38,11 @@
* Execute SQL DECLARE CURSOR command. * Execute SQL DECLARE CURSOR command.
*/ */
void void
PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params) PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params,
const char *queryString, bool isTopLevel)
{ {
Oid *param_types;
int num_params;
List *rewritten; List *rewritten;
Query *query; Query *query;
PlannedStmt *plan; PlannedStmt *plan;
...@@ -61,40 +64,53 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params) ...@@ -61,40 +64,53 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params)
* user-visible effect). * user-visible effect).
*/ */
if (!(stmt->options & CURSOR_OPT_HOLD)) if (!(stmt->options & CURSOR_OPT_HOLD))
RequireTransactionChain((void *) stmt, "DECLARE CURSOR"); RequireTransactionChain(isTopLevel, "DECLARE CURSOR");
/* /*
* Because the planner is not cool about not scribbling on its input, we * Don't allow both SCROLL and NO SCROLL to be specified
* make a preliminary copy of the source querytree. This prevents
* problems in the case that the DECLARE CURSOR is in a portal and is
* executed repeatedly. XXX the planner really shouldn't modify its input
* ... FIXME someday.
*/ */
query = copyObject(stmt->query); if ((stmt->options & CURSOR_OPT_SCROLL) &&
(stmt->options & CURSOR_OPT_NO_SCROLL))
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
errmsg("cannot specify both SCROLL and NO SCROLL")));
/* Convert parameter type data to the form parser wants */
getParamListTypes(params, &param_types, &num_params);
/* /*
* The query has been through parse analysis, but not rewriting or * Run parse analysis and rewrite. Note this also acquires sufficient
* planning as yet. Note that the grammar ensured we have a SELECT query, * locks on the source table(s).
* so we are not expecting rule rewriting to do anything strange. *
* Because the parser and planner tend to scribble on their input, we
* make a preliminary copy of the source querytree. This prevents
* problems in the case that the DECLARE CURSOR is in a portal or plpgsql
* function and is executed repeatedly. (See also the same hack in
* COPY and PREPARE.) XXX FIXME someday.
*/ */
AcquireRewriteLocks(query); rewritten = pg_analyze_and_rewrite((Node *) copyObject(stmt->query),
rewritten = QueryRewrite(query); queryString, param_types, num_params);
/* We don't expect more or less than one result query */
if (list_length(rewritten) != 1 || !IsA(linitial(rewritten), Query)) if (list_length(rewritten) != 1 || !IsA(linitial(rewritten), Query))
elog(ERROR, "unexpected rewrite result"); elog(ERROR, "unexpected rewrite result");
query = (Query *) linitial(rewritten); query = (Query *) linitial(rewritten);
if (query->commandType != CMD_SELECT) if (query->commandType != CMD_SELECT)
elog(ERROR, "unexpected rewrite result"); elog(ERROR, "unexpected rewrite result");
/* But we must explicitly disallow DECLARE CURSOR ... SELECT INTO */
if (query->into) if (query->into)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION), (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
errmsg("DECLARE CURSOR cannot specify INTO"))); errmsg("DECLARE CURSOR cannot specify INTO")));
if (query->rowMarks != NIL) if (query->rowMarks != NIL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("DECLARE CURSOR ... FOR UPDATE/SHARE is not supported"), errmsg("DECLARE CURSOR ... FOR UPDATE/SHARE is not supported"),
errdetail("Cursors must be READ ONLY."))); errdetail("Cursors must be READ ONLY.")));
/* plan the query */
plan = planner(query, true, stmt->options, params); plan = planner(query, true, stmt->options, params);
/* /*
...@@ -106,23 +122,22 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params) ...@@ -106,23 +122,22 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params)
plan = copyObject(plan); plan = copyObject(plan);
/*
* XXX: debug_query_string is wrong here: the user might have submitted
* multiple semicolon delimited queries.
*/
PortalDefineQuery(portal, PortalDefineQuery(portal,
NULL, NULL,
debug_query_string ? pstrdup(debug_query_string) : NULL, queryString,
"SELECT", /* cursor's query is always a SELECT */ "SELECT", /* cursor's query is always a SELECT */
list_make1(plan), list_make1(plan),
PortalGetHeapMemory(portal)); NULL);
/* /*----------
* Also copy the outer portal's parameter list into the inner portal's * Also copy the outer portal's parameter list into the inner portal's
* memory context. We want to pass down the parameter values in case we * memory context. We want to pass down the parameter values in case we
* had a command like DECLARE c CURSOR FOR SELECT ... WHERE foo = $1 This * had a command like
* will have been parsed using the outer parameter set and the parameter * DECLARE c CURSOR FOR SELECT ... WHERE foo = $1
* value needs to be preserved for use when the cursor is executed. * This will have been parsed using the outer parameter set and the
* parameter value needs to be preserved for use when the cursor is
* executed.
*----------
*/ */
params = copyParamList(params); params = copyParamList(params);
...@@ -314,7 +329,6 @@ PersistHoldablePortal(Portal portal) ...@@ -314,7 +329,6 @@ PersistHoldablePortal(Portal portal)
Snapshot saveActiveSnapshot; Snapshot saveActiveSnapshot;
ResourceOwner saveResourceOwner; ResourceOwner saveResourceOwner;
MemoryContext savePortalContext; MemoryContext savePortalContext;
MemoryContext saveQueryContext;
MemoryContext oldcxt; MemoryContext oldcxt;
/* /*
...@@ -356,14 +370,12 @@ PersistHoldablePortal(Portal portal) ...@@ -356,14 +370,12 @@ PersistHoldablePortal(Portal portal)
saveActiveSnapshot = ActiveSnapshot; saveActiveSnapshot = ActiveSnapshot;
saveResourceOwner = CurrentResourceOwner; saveResourceOwner = CurrentResourceOwner;
savePortalContext = PortalContext; savePortalContext = PortalContext;
saveQueryContext = QueryContext;
PG_TRY(); PG_TRY();
{ {
ActivePortal = portal; ActivePortal = portal;
ActiveSnapshot = queryDesc->snapshot; ActiveSnapshot = queryDesc->snapshot;
CurrentResourceOwner = portal->resowner; CurrentResourceOwner = portal->resowner;
PortalContext = PortalGetHeapMemory(portal); PortalContext = PortalGetHeapMemory(portal);
QueryContext = portal->queryContext;
MemoryContextSwitchTo(PortalContext); MemoryContextSwitchTo(PortalContext);
...@@ -434,7 +446,6 @@ PersistHoldablePortal(Portal portal) ...@@ -434,7 +446,6 @@ PersistHoldablePortal(Portal portal)
ActiveSnapshot = saveActiveSnapshot; ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner; CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext; PortalContext = savePortalContext;
QueryContext = saveQueryContext;
PG_RE_THROW(); PG_RE_THROW();
} }
...@@ -449,7 +460,6 @@ PersistHoldablePortal(Portal portal) ...@@ -449,7 +460,6 @@ PersistHoldablePortal(Portal portal)
ActiveSnapshot = saveActiveSnapshot; ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner; CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext; PortalContext = savePortalContext;
QueryContext = saveQueryContext;
/* /*
* We can now release any subsidiary memory of the portal's heap context; * We can now release any subsidiary memory of the portal's heap context;
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.43 2007/02/01 19:10:26 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.44 2007/03/13 00:33:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -38,7 +38,7 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI ...@@ -38,7 +38,7 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI
* CREATE SCHEMA * CREATE SCHEMA
*/ */
void void
CreateSchemaCommand(CreateSchemaStmt *stmt) CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
{ {
const char *schemaName = stmt->schemaname; const char *schemaName = stmt->schemaname;
const char *authId = stmt->authid; const char *authId = stmt->authid;
...@@ -122,7 +122,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) ...@@ -122,7 +122,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
List *querytree_list; List *querytree_list;
ListCell *querytree_item; ListCell *querytree_item;
querytree_list = parse_analyze(parsetree, NULL, NULL, 0); querytree_list = parse_analyze(parsetree, queryString, NULL, 0);
foreach(querytree_item, querytree_list) foreach(querytree_item, querytree_list)
{ {
...@@ -131,7 +131,12 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) ...@@ -131,7 +131,12 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
/* schemas should contain only utility stmts */ /* schemas should contain only utility stmts */
Assert(querytree->commandType == CMD_UTILITY); Assert(querytree->commandType == CMD_UTILITY);
/* do this step */ /* do this step */
ProcessUtility(querytree->utilityStmt, NULL, None_Receiver, NULL); ProcessUtility(querytree->utilityStmt,
queryString,
NULL,
false, /* not top level */
None_Receiver,
NULL);
/* make sure later steps can see the object created here */ /* make sure later steps can see the object created here */
CommandCounterIncrement(); CommandCounterIncrement();
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.216 2007/03/06 02:06:13 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.217 2007/03/13 00:33:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -3696,6 +3696,13 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel, ...@@ -3696,6 +3696,13 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
/* suppress notices when rebuilding existing index */ /* suppress notices when rebuilding existing index */
quiet = is_rebuild; quiet = is_rebuild;
/*
* Run parse analysis. We don't have convenient access to the query text
* here, but it's probably not worth worrying about.
*/
stmt = analyzeIndexStmt(stmt, NULL);
/* ... and do it */
DefineIndex(stmt->relation, /* relation */ DefineIndex(stmt->relation, /* relation */
stmt->idxname, /* index name */ stmt->idxname, /* index name */
InvalidOid, /* no predefined OID */ InvalidOid, /* no predefined OID */
...@@ -3703,7 +3710,6 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel, ...@@ -3703,7 +3710,6 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
stmt->tableSpace, stmt->tableSpace,
stmt->indexParams, /* parameters */ stmt->indexParams, /* parameters */
(Expr *) stmt->whereClause, (Expr *) stmt->whereClause,
stmt->rangetable,
stmt->options, stmt->options,
stmt->unique, stmt->unique,
stmt->primary, stmt->primary,
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.43 2007/03/06 02:06:13 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.44 2007/03/13 00:33:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -198,11 +198,6 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) ...@@ -198,11 +198,6 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
char *linkloc; char *linkloc;
Oid ownerId; Oid ownerId;
/* validate */
/* don't call this in a transaction block */
PreventTransactionChain((void *) stmt, "CREATE TABLESPACE");
/* Must be super user */ /* Must be super user */
if (!superuser()) if (!superuser())
ereport(ERROR, ereport(ERROR,
...@@ -385,9 +380,6 @@ DropTableSpace(DropTableSpaceStmt *stmt) ...@@ -385,9 +380,6 @@ DropTableSpace(DropTableSpaceStmt *stmt)
ScanKeyData entry[1]; ScanKeyData entry[1];
Oid tablespaceoid; Oid tablespaceoid;
/* don't call this in a transaction block */
PreventTransactionChain((void *) stmt, "DROP TABLESPACE");
/* /*
* Find the target tuple * Find the target tuple
*/ */
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.347 2007/03/08 17:03:31 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.348 2007/03/13 00:33:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -257,13 +257,14 @@ static Size PageGetFreeSpaceWithFillFactor(Relation relation, Page page); ...@@ -257,13 +257,14 @@ static Size PageGetFreeSpaceWithFillFactor(Relation relation, Page page);
* relation OIDs to be processed, and vacstmt->relation is ignored. * relation OIDs to be processed, and vacstmt->relation is ignored.
* (The non-NIL case is currently only used by autovacuum.) * (The non-NIL case is currently only used by autovacuum.)
* *
* isTopLevel should be passed down from ProcessUtility.
*
* It is the caller's responsibility that both vacstmt and relids * It is the caller's responsibility that both vacstmt and relids
* (if given) be allocated in a memory context that won't disappear * (if given) be allocated in a memory context that won't disappear
* at transaction commit. In fact this context must be QueryContext * at transaction commit.
* to avoid complaints from PreventTransactionChain.
*/ */
void void
vacuum(VacuumStmt *vacstmt, List *relids) vacuum(VacuumStmt *vacstmt, List *relids, bool isTopLevel)
{ {
const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE"; const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
volatile MemoryContext anl_context = NULL; volatile MemoryContext anl_context = NULL;
...@@ -293,11 +294,11 @@ vacuum(VacuumStmt *vacstmt, List *relids) ...@@ -293,11 +294,11 @@ vacuum(VacuumStmt *vacstmt, List *relids)
*/ */
if (vacstmt->vacuum) if (vacstmt->vacuum)
{ {
PreventTransactionChain((void *) vacstmt, stmttype); PreventTransactionChain(isTopLevel, stmttype);
in_outer_xact = false; in_outer_xact = false;
} }
else else
in_outer_xact = IsInTransactionChain((void *) vacstmt); in_outer_xact = IsInTransactionChain(isTopLevel);
/* /*
* Send info about dead objects to the statistics collector, unless we are * Send info about dead objects to the statistics collector, unless we are
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.99 2007/01/05 22:19:27 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.100 2007/03/13 00:33:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "parser/analyze.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "parser/parse_relation.h" #include "parser/parse_relation.h"
#include "rewrite/rewriteDefine.h" #include "rewrite/rewriteDefine.h"
...@@ -258,54 +259,23 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc) ...@@ -258,54 +259,23 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc)
*/ */
} }
static RuleStmt *
FormViewRetrieveRule(const RangeVar *view, Query *viewParse, bool replace)
{
RuleStmt *rule;
/*
* Create a RuleStmt that corresponds to the suitable rewrite rule args
* for DefineQueryRewrite();
*/
rule = makeNode(RuleStmt);
rule->relation = copyObject((RangeVar *) view);
rule->rulename = pstrdup(ViewSelectRuleName);
rule->whereClause = NULL;
rule->event = CMD_SELECT;
rule->instead = true;
rule->actions = list_make1(viewParse);
rule->replace = replace;
return rule;
}
static void static void
DefineViewRules(const RangeVar *view, Query *viewParse, bool replace) DefineViewRules(const RangeVar *view, Query *viewParse, bool replace)
{ {
RuleStmt *retrieve_rule; /*
* Set up the ON SELECT rule. Since the query has already been through
#ifdef NOTYET * parse analysis, we use DefineQueryRewrite() directly.
RuleStmt *replace_rule; */
RuleStmt *append_rule; DefineQueryRewrite(pstrdup(ViewSelectRuleName),
RuleStmt *delete_rule; (RangeVar *) copyObject((RangeVar *) view),
#endif NULL,
CMD_SELECT,
retrieve_rule = FormViewRetrieveRule(view, viewParse, replace); true,
replace,
#ifdef NOTYET list_make1(viewParse));
replace_rule = FormViewReplaceRule(view, viewParse); /*
append_rule = FormViewAppendRule(view, viewParse); * Someday: automatic ON INSERT, etc
delete_rule = FormViewDeleteRule(view, viewParse); */
#endif
DefineQueryRewrite(retrieve_rule);
#ifdef NOTYET
DefineQueryRewrite(replace_rule);
DefineQueryRewrite(append_rule);
DefineQueryRewrite(delete_rule);
#endif
} }
/*--------------------------------------------------------------- /*---------------------------------------------------------------
...@@ -374,34 +344,80 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse) ...@@ -374,34 +344,80 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
return viewParse; return viewParse;
} }
/*------------------------------------------------------------------- /*
* DefineView * DefineView
* * Execute a CREATE VIEW command.
* - takes a "viewname", "parsetree" pair and then
* 1) construct the "virtual" relation
* 2) commit the command but NOT the transaction,
* so that the relation exists
* before the rules are defined.
* 2) define the "n" rules specified in the PRS2 paper
* over the "virtual" relation
*-------------------------------------------------------------------
*/ */
void void
DefineView(RangeVar *view, Query *viewParse, bool replace) DefineView(ViewStmt *stmt, const char *queryString)
{ {
List *stmts;
Query *viewParse;
Oid viewOid; Oid viewOid;
RangeVar *view;
/*
* Run parse analysis to convert the raw parse tree to a Query. Note
* this also acquires sufficient locks on the source table(s).
*
* Since parse analysis scribbles on its input, copy the raw parse tree;
* this ensures we don't corrupt a prepared statement, for example.
*/
stmts = parse_analyze((Node *) copyObject(stmt->query),
queryString, NULL, 0);
/*
* The grammar should ensure that the result is a single SELECT Query.
*/
if (list_length(stmts) != 1)
elog(ERROR, "unexpected parse analysis result");
viewParse = (Query *) linitial(stmts);
if (!IsA(viewParse, Query) ||
viewParse->commandType != CMD_SELECT)
elog(ERROR, "unexpected parse analysis result");
/*
* If a list of column names was given, run through and insert these into
* the actual query tree. - thomas 2000-03-08
*/
if (stmt->aliases != NIL)
{
ListCell *alist_item = list_head(stmt->aliases);
ListCell *targetList;
foreach(targetList, viewParse->targetList)
{
TargetEntry *te = (TargetEntry *) lfirst(targetList);
Assert(IsA(te, TargetEntry));
/* junk columns don't get aliases */
if (te->resjunk)
continue;
te->resname = pstrdup(strVal(lfirst(alist_item)));
alist_item = lnext(alist_item);
if (alist_item == NULL)
break; /* done assigning aliases */
}
if (alist_item != NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("CREATE VIEW specifies more column "
"names than columns")));
}
/* /*
* If the user didn't explicitly ask for a temporary view, check whether * If the user didn't explicitly ask for a temporary view, check whether
* we need one implicitly. * we need one implicitly.
*/ */
if (!view->istemp) view = stmt->view;
if (!view->istemp && isViewOnTempTable(viewParse))
{ {
view->istemp = isViewOnTempTable(viewParse); view = copyObject(view); /* don't corrupt original command */
if (view->istemp) view->istemp = true;
ereport(NOTICE, ereport(NOTICE,
(errmsg("view \"%s\" will be a temporary view", (errmsg("view \"%s\" will be a temporary view",
view->relname))); view->relname)));
} }
/* /*
...@@ -410,7 +426,8 @@ DefineView(RangeVar *view, Query *viewParse, bool replace) ...@@ -410,7 +426,8 @@ DefineView(RangeVar *view, Query *viewParse, bool replace)
* NOTE: if it already exists and replace is false, the xact will be * NOTE: if it already exists and replace is false, the xact will be
* aborted. * aborted.
*/ */
viewOid = DefineVirtualRelation(view, viewParse->targetList, replace); viewOid = DefineVirtualRelation(view, viewParse->targetList,
stmt->replace);
/* /*
* The relation we have just created is not visible to any other commands * The relation we have just created is not visible to any other commands
...@@ -428,7 +445,7 @@ DefineView(RangeVar *view, Query *viewParse, bool replace) ...@@ -428,7 +445,7 @@ DefineView(RangeVar *view, Query *viewParse, bool replace)
/* /*
* Now create the rules associated with the view. * Now create the rules associated with the view.
*/ */
DefineViewRules(view, viewParse, replace); DefineViewRules(view, viewParse, stmt->replace);
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.111 2007/02/20 17:32:15 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.112 2007/03/13 00:33:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -58,6 +58,8 @@ typedef struct local_es ...@@ -58,6 +58,8 @@ typedef struct local_es
*/ */
typedef struct typedef struct
{ {
char *src; /* function body text (for error msgs) */
Oid *argtypes; /* resolved types of arguments */ Oid *argtypes; /* resolved types of arguments */
Oid rettype; /* actual return type */ Oid rettype; /* actual return type */
int16 typlen; /* length of the return type */ int16 typlen; /* length of the return type */
...@@ -82,7 +84,8 @@ static execution_state *init_execution_state(List *queryTree_list, ...@@ -82,7 +84,8 @@ static execution_state *init_execution_state(List *queryTree_list,
bool readonly_func); bool readonly_func);
static void init_sql_fcache(FmgrInfo *finfo); static void init_sql_fcache(FmgrInfo *finfo);
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache); static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
static TupleTableSlot *postquel_getnext(execution_state *es); static TupleTableSlot *postquel_getnext(execution_state *es,
SQLFunctionCachePtr fcache);
static void postquel_end(execution_state *es); static void postquel_end(execution_state *es);
static void postquel_sub_params(SQLFunctionCachePtr fcache, static void postquel_sub_params(SQLFunctionCachePtr fcache,
FunctionCallInfo fcinfo); FunctionCallInfo fcinfo);
...@@ -156,7 +159,6 @@ init_sql_fcache(FmgrInfo *finfo) ...@@ -156,7 +159,6 @@ init_sql_fcache(FmgrInfo *finfo)
Form_pg_proc procedureStruct; Form_pg_proc procedureStruct;
SQLFunctionCachePtr fcache; SQLFunctionCachePtr fcache;
Oid *argOidVect; Oid *argOidVect;
char *src;
int nargs; int nargs;
List *queryTree_list; List *queryTree_list;
Datum tmp; Datum tmp;
...@@ -233,7 +235,7 @@ init_sql_fcache(FmgrInfo *finfo) ...@@ -233,7 +235,7 @@ init_sql_fcache(FmgrInfo *finfo)
fcache->argtypes = argOidVect; fcache->argtypes = argOidVect;
/* /*
* Parse and rewrite the queries in the function text. * And of course we need the function body text.
*/ */
tmp = SysCacheGetAttr(PROCOID, tmp = SysCacheGetAttr(PROCOID,
procedureTuple, procedureTuple,
...@@ -241,9 +243,12 @@ init_sql_fcache(FmgrInfo *finfo) ...@@ -241,9 +243,12 @@ init_sql_fcache(FmgrInfo *finfo)
&isNull); &isNull);
if (isNull) if (isNull)
elog(ERROR, "null prosrc for function %u", foid); elog(ERROR, "null prosrc for function %u", foid);
src = DatumGetCString(DirectFunctionCall1(textout, tmp)); fcache->src = DatumGetCString(DirectFunctionCall1(textout, tmp));
queryTree_list = pg_parse_and_rewrite(src, argOidVect, nargs); /*
* Parse and rewrite the queries in the function text.
*/
queryTree_list = pg_parse_and_rewrite(fcache->src, argOidVect, nargs);
/* /*
* Check that the function returns the type it claims to. Although * Check that the function returns the type it claims to. Although
...@@ -270,8 +275,6 @@ init_sql_fcache(FmgrInfo *finfo) ...@@ -270,8 +275,6 @@ init_sql_fcache(FmgrInfo *finfo)
fcache->func_state = init_execution_state(queryTree_list, fcache->func_state = init_execution_state(queryTree_list,
fcache->readonly_func); fcache->readonly_func);
pfree(src);
ReleaseSysCache(procedureTuple); ReleaseSysCache(procedureTuple);
finfo->fn_extra = (void *) fcache; finfo->fn_extra = (void *) fcache;
...@@ -331,7 +334,7 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache) ...@@ -331,7 +334,7 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
} }
static TupleTableSlot * static TupleTableSlot *
postquel_getnext(execution_state *es) postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
{ {
TupleTableSlot *result; TupleTableSlot *result;
Snapshot saveActiveSnapshot; Snapshot saveActiveSnapshot;
...@@ -345,8 +348,12 @@ postquel_getnext(execution_state *es) ...@@ -345,8 +348,12 @@ postquel_getnext(execution_state *es)
if (es->qd->operation == CMD_UTILITY) if (es->qd->operation == CMD_UTILITY)
{ {
ProcessUtility(es->qd->utilitystmt, es->qd->params, ProcessUtility(es->qd->utilitystmt,
es->qd->dest, NULL); fcache->src,
es->qd->params,
false, /* not top level */
es->qd->dest,
NULL);
result = NULL; result = NULL;
} }
else else
...@@ -465,7 +472,7 @@ postquel_execute(execution_state *es, ...@@ -465,7 +472,7 @@ postquel_execute(execution_state *es,
if (es->status == F_EXEC_START) if (es->status == F_EXEC_START)
postquel_start(es, fcache); postquel_start(es, fcache);
slot = postquel_getnext(es); slot = postquel_getnext(es, fcache);
if (TupIsNull(slot)) if (TupIsNull(slot))
{ {
...@@ -754,21 +761,11 @@ sql_exec_error_callback(void *arg) ...@@ -754,21 +761,11 @@ sql_exec_error_callback(void *arg)
* If there is a syntax error position, convert to internal syntax error * If there is a syntax error position, convert to internal syntax error
*/ */
syntaxerrposition = geterrposition(); syntaxerrposition = geterrposition();
if (syntaxerrposition > 0) if (syntaxerrposition > 0 && fcache->src)
{ {
bool isnull;
Datum tmp;
char *prosrc;
tmp = SysCacheGetAttr(PROCOID, func_tuple, Anum_pg_proc_prosrc,
&isnull);
if (isnull)
elog(ERROR, "null prosrc");
prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
errposition(0); errposition(0);
internalerrposition(syntaxerrposition); internalerrposition(syntaxerrposition);
internalerrquery(prosrc); internalerrquery(fcache->src);
pfree(prosrc);
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.170 2007/02/20 17:32:15 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.171 2007/03/13 00:33:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -927,7 +927,7 @@ SPI_cursor_open(const char *name, void *plan, ...@@ -927,7 +927,7 @@ SPI_cursor_open(const char *name, void *plan,
spiplan->query, spiplan->query,
CreateCommandTag(PortalListGetPrimaryStmt(stmt_list)), CreateCommandTag(PortalListGetPrimaryStmt(stmt_list)),
stmt_list, stmt_list,
PortalGetHeapMemory(portal)); NULL);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
...@@ -1471,7 +1471,12 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, ...@@ -1471,7 +1471,12 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
} }
else else
{ {
ProcessUtility(stmt, paramLI, dest, NULL); ProcessUtility(stmt,
NULL, /* XXX provide query string? */
paramLI,
false, /* not top level */
dest,
NULL);
/* Update "processed" if stmt returned tuples */ /* Update "processed" if stmt returned tuples */
if (_SPI_current->tuptable) if (_SPI_current->tuptable)
_SPI_current->processed = _SPI_current->tuptable->alloced - _SPI_current->tuptable->free; _SPI_current->processed = _SPI_current->tuptable->alloced - _SPI_current->tuptable->free;
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.369 2007/02/27 01:11:25 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.370 2007/03/13 00:33:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2142,7 +2142,6 @@ _copyIndexStmt(IndexStmt *from) ...@@ -2142,7 +2142,6 @@ _copyIndexStmt(IndexStmt *from)
COPY_NODE_FIELD(indexParams); COPY_NODE_FIELD(indexParams);
COPY_NODE_FIELD(options); COPY_NODE_FIELD(options);
COPY_NODE_FIELD(whereClause); COPY_NODE_FIELD(whereClause);
COPY_NODE_FIELD(rangetable);
COPY_SCALAR_FIELD(unique); COPY_SCALAR_FIELD(unique);
COPY_SCALAR_FIELD(primary); COPY_SCALAR_FIELD(primary);
COPY_SCALAR_FIELD(isconstraint); COPY_SCALAR_FIELD(isconstraint);
...@@ -2785,7 +2784,6 @@ _copyPrepareStmt(PrepareStmt *from) ...@@ -2785,7 +2784,6 @@ _copyPrepareStmt(PrepareStmt *from)
COPY_STRING_FIELD(name); COPY_STRING_FIELD(name);
COPY_NODE_FIELD(argtypes); COPY_NODE_FIELD(argtypes);
COPY_NODE_FIELD(argtype_oids);
COPY_NODE_FIELD(query); COPY_NODE_FIELD(query);
return newnode; return newnode;
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.300 2007/02/22 22:00:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.301 2007/03/13 00:33:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -994,7 +994,6 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b) ...@@ -994,7 +994,6 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b)
COMPARE_NODE_FIELD(indexParams); COMPARE_NODE_FIELD(indexParams);
COMPARE_NODE_FIELD(options); COMPARE_NODE_FIELD(options);
COMPARE_NODE_FIELD(whereClause); COMPARE_NODE_FIELD(whereClause);
COMPARE_NODE_FIELD(rangetable);
COMPARE_SCALAR_FIELD(unique); COMPARE_SCALAR_FIELD(unique);
COMPARE_SCALAR_FIELD(primary); COMPARE_SCALAR_FIELD(primary);
COMPARE_SCALAR_FIELD(isconstraint); COMPARE_SCALAR_FIELD(isconstraint);
...@@ -1536,7 +1535,6 @@ _equalPrepareStmt(PrepareStmt *a, PrepareStmt *b) ...@@ -1536,7 +1535,6 @@ _equalPrepareStmt(PrepareStmt *a, PrepareStmt *b)
{ {
COMPARE_STRING_FIELD(name); COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(argtypes); COMPARE_NODE_FIELD(argtypes);
COMPARE_NODE_FIELD(argtype_oids);
COMPARE_NODE_FIELD(query); COMPARE_NODE_FIELD(query);
return true; return true;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.302 2007/02/27 01:11:25 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.303 2007/03/13 00:33:40 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -1505,7 +1505,6 @@ _outIndexStmt(StringInfo str, IndexStmt *node) ...@@ -1505,7 +1505,6 @@ _outIndexStmt(StringInfo str, IndexStmt *node)
WRITE_NODE_FIELD(indexParams); WRITE_NODE_FIELD(indexParams);
WRITE_NODE_FIELD(options); WRITE_NODE_FIELD(options);
WRITE_NODE_FIELD(whereClause); WRITE_NODE_FIELD(whereClause);
WRITE_NODE_FIELD(rangetable);
WRITE_BOOL_FIELD(unique); WRITE_BOOL_FIELD(unique);
WRITE_BOOL_FIELD(primary); WRITE_BOOL_FIELD(primary);
WRITE_BOOL_FIELD(isconstraint); WRITE_BOOL_FIELD(isconstraint);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/params.c,v 1.8 2007/01/05 22:19:30 momjian Exp $ * $PostgreSQL: pgsql/src/backend/nodes/params.c,v 1.9 2007/03/13 00:33:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -60,3 +60,34 @@ copyParamList(ParamListInfo from) ...@@ -60,3 +60,34 @@ copyParamList(ParamListInfo from)
return retval; return retval;
} }
/*
* Extract an array of parameter type OIDs from a ParamListInfo.
*
* The result is allocated in CurrentMemoryContext.
*/
void
getParamListTypes(ParamListInfo params,
Oid **param_types, int *num_params)
{
Oid *ptypes;
int i;
if (params == NULL || params->numParams <= 0)
{
*param_types = NULL;
*num_params = 0;
return;
}
ptypes = (Oid *) palloc(params->numParams * sizeof(Oid));
*param_types = ptypes;
*num_params = params->numParams;
for (i = 0; i < params->numParams; i++)
{
ParamExternData *prm = &params->params[i];
ptypes[i] = prm->ptype;
}
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.237 2007/03/06 22:45:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.238 2007/03/13 00:33:41 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -3603,38 +3603,6 @@ query_tree_walker(Query *query, ...@@ -3603,38 +3603,6 @@ query_tree_walker(Query *query,
return true; return true;
if (range_table_walker(query->rtable, walker, context, flags)) if (range_table_walker(query->rtable, walker, context, flags))
return true; return true;
if (query->utilityStmt)
{
/*
* Certain utility commands contain general-purpose Querys embedded in
* them --- if this is one, invoke the walker on the sub-Query.
*/
if (IsA(query->utilityStmt, CopyStmt))
{
if (walker(((CopyStmt *) query->utilityStmt)->query, context))
return true;
}
if (IsA(query->utilityStmt, DeclareCursorStmt))
{
if (walker(((DeclareCursorStmt *) query->utilityStmt)->query, context))
return true;
}
if (IsA(query->utilityStmt, ExplainStmt))
{
if (walker(((ExplainStmt *) query->utilityStmt)->query, context))
return true;
}
if (IsA(query->utilityStmt, PrepareStmt))
{
if (walker(((PrepareStmt *) query->utilityStmt)->query, context))
return true;
}
if (IsA(query->utilityStmt, ViewStmt))
{
if (walker(((ViewStmt *) query->utilityStmt)->query, context))
return true;
}
}
return false; return false;
} }
......
This diff is collapsed.
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.580 2007/02/20 17:32:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.581 2007/03/13 00:33:41 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -1662,7 +1662,7 @@ CopyStmt: COPY opt_binary qualified_name opt_column_list opt_oids ...@@ -1662,7 +1662,7 @@ CopyStmt: COPY opt_binary qualified_name opt_column_list opt_oids
{ {
CopyStmt *n = makeNode(CopyStmt); CopyStmt *n = makeNode(CopyStmt);
n->relation = NULL; n->relation = NULL;
n->query = (Query *) $2; n->query = $2;
n->attlist = NIL; n->attlist = NIL;
n->is_from = false; n->is_from = false;
n->filename = $4; n->filename = $4;
...@@ -4959,22 +4959,22 @@ ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list ...@@ -4959,22 +4959,22 @@ ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list
AS SelectStmt opt_check_option AS SelectStmt opt_check_option
{ {
ViewStmt *n = makeNode(ViewStmt); ViewStmt *n = makeNode(ViewStmt);
n->replace = false;
n->view = $4; n->view = $4;
n->view->istemp = $2; n->view->istemp = $2;
n->aliases = $5; n->aliases = $5;
n->query = (Query *) $7; n->query = $7;
n->replace = false;
$$ = (Node *) n; $$ = (Node *) n;
} }
| CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list | CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list
AS SelectStmt opt_check_option AS SelectStmt opt_check_option
{ {
ViewStmt *n = makeNode(ViewStmt); ViewStmt *n = makeNode(ViewStmt);
n->replace = true;
n->view = $6; n->view = $6;
n->view->istemp = $4; n->view->istemp = $4;
n->aliases = $7; n->aliases = $7;
n->query = (Query *) $9; n->query = $9;
n->replace = true;
$$ = (Node *) n; $$ = (Node *) n;
} }
; ;
...@@ -5406,7 +5406,7 @@ ExplainStmt: EXPLAIN opt_analyze opt_verbose ExplainableStmt ...@@ -5406,7 +5406,7 @@ ExplainStmt: EXPLAIN opt_analyze opt_verbose ExplainableStmt
ExplainStmt *n = makeNode(ExplainStmt); ExplainStmt *n = makeNode(ExplainStmt);
n->analyze = $2; n->analyze = $2;
n->verbose = $3; n->verbose = $3;
n->query = (Query*)$4; n->query = $4;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
...@@ -5437,7 +5437,7 @@ PrepareStmt: PREPARE name prep_type_clause AS PreparableStmt ...@@ -5437,7 +5437,7 @@ PrepareStmt: PREPARE name prep_type_clause AS PreparableStmt
PrepareStmt *n = makeNode(PrepareStmt); PrepareStmt *n = makeNode(PrepareStmt);
n->name = $2; n->name = $2;
n->argtypes = $3; n->argtypes = $3;
n->query = (Query *) $5; n->query = $5;
$$ = (Node *) n; $$ = (Node *) n;
} }
; ;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.33 2007/03/07 13:35:02 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.34 2007/03/13 00:33:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1248,13 +1248,6 @@ autovacuum_do_vac_analyze(Oid relid, bool dovacuum, bool doanalyze, ...@@ -1248,13 +1248,6 @@ autovacuum_do_vac_analyze(Oid relid, bool dovacuum, bool doanalyze,
vacstmt = makeNode(VacuumStmt); vacstmt = makeNode(VacuumStmt);
/*
* Point QueryContext to the autovac memory context to fake out the
* PreventTransactionChain check inside vacuum(). Note that this is also
* why we palloc vacstmt instead of just using a local variable.
*/
QueryContext = CurrentMemoryContext;
/* Set up command parameters */ /* Set up command parameters */
vacstmt->vacuum = dovacuum; vacstmt->vacuum = dovacuum;
vacstmt->full = false; vacstmt->full = false;
...@@ -1267,7 +1260,7 @@ autovacuum_do_vac_analyze(Oid relid, bool dovacuum, bool doanalyze, ...@@ -1267,7 +1260,7 @@ autovacuum_do_vac_analyze(Oid relid, bool dovacuum, bool doanalyze,
/* Let pgstat know what we're doing */ /* Let pgstat know what we're doing */
autovac_report_activity(vacstmt, relid); autovac_report_activity(vacstmt, relid);
vacuum(vacstmt, list_make1_oid(relid)); vacuum(vacstmt, list_make1_oid(relid), true);
pfree(vacstmt); pfree(vacstmt);
MemoryContextSwitchTo(old_cxt); MemoryContextSwitchTo(old_cxt);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.117 2007/02/01 19:10:27 momjian Exp $ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.118 2007/03/13 00:33:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "catalog/pg_rewrite.h" #include "catalog/pg_rewrite.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "parser/analyze.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "rewrite/rewriteDefine.h" #include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteManip.h" #include "rewrite/rewriteManip.h"
...@@ -177,15 +178,46 @@ InsertRule(char *rulname, ...@@ -177,15 +178,46 @@ InsertRule(char *rulname,
return rewriteObjectId; return rewriteObjectId;
} }
/*
* DefineRule
* Execute a CREATE RULE command.
*/
void
DefineRule(RuleStmt *stmt, const char *queryString)
{
List *actions;
Node *whereClause;
/* Parse analysis ... */
analyzeRuleStmt(stmt, queryString, &actions, &whereClause);
/* ... and execution */
DefineQueryRewrite(stmt->rulename,
stmt->relation,
whereClause,
stmt->event,
stmt->instead,
stmt->replace,
actions);
}
/*
* DefineQueryRewrite
* Create a rule
*
* This is essentially the same as DefineRule() except that the rule's
* action and qual have already been passed through parse analysis.
*/
void void
DefineQueryRewrite(RuleStmt *stmt) DefineQueryRewrite(char *rulename,
RangeVar *event_obj,
Node *event_qual,
CmdType event_type,
bool is_instead,
bool replace,
List *action)
{ {
RangeVar *event_obj = stmt->relation;
Node *event_qual = stmt->whereClause;
CmdType event_type = stmt->event;
bool is_instead = stmt->instead;
bool replace = stmt->replace;
List *action = stmt->actions;
Relation event_relation; Relation event_relation;
Oid ev_relid; Oid ev_relid;
Oid ruleId; Oid ruleId;
...@@ -304,7 +336,7 @@ DefineQueryRewrite(RuleStmt *stmt) ...@@ -304,7 +336,7 @@ DefineQueryRewrite(RuleStmt *stmt)
/* /*
* ... and finally the rule must be named _RETURN. * ... and finally the rule must be named _RETURN.
*/ */
if (strcmp(stmt->rulename, ViewSelectRuleName) != 0) if (strcmp(rulename, ViewSelectRuleName) != 0)
{ {
/* /*
* In versions before 7.3, the expected name was _RETviewname. For * In versions before 7.3, the expected name was _RETviewname. For
...@@ -315,14 +347,14 @@ DefineQueryRewrite(RuleStmt *stmt) ...@@ -315,14 +347,14 @@ DefineQueryRewrite(RuleStmt *stmt)
* worry about where a multibyte character might have gotten * worry about where a multibyte character might have gotten
* truncated. * truncated.
*/ */
if (strncmp(stmt->rulename, "_RET", 4) != 0 || if (strncmp(rulename, "_RET", 4) != 0 ||
strncmp(stmt->rulename + 4, event_obj->relname, strncmp(rulename + 4, event_obj->relname,
NAMEDATALEN - 4 - 4) != 0) NAMEDATALEN - 4 - 4) != 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("view rule for \"%s\" must be named \"%s\"", errmsg("view rule for \"%s\" must be named \"%s\"",
event_obj->relname, ViewSelectRuleName))); event_obj->relname, ViewSelectRuleName)));
stmt->rulename = pstrdup(ViewSelectRuleName); rulename = pstrdup(ViewSelectRuleName);
} }
/* /*
...@@ -411,7 +443,7 @@ DefineQueryRewrite(RuleStmt *stmt) ...@@ -411,7 +443,7 @@ DefineQueryRewrite(RuleStmt *stmt)
/* discard rule if it's null action and not INSTEAD; it's a no-op */ /* discard rule if it's null action and not INSTEAD; it's a no-op */
if (action != NIL || is_instead) if (action != NIL || is_instead)
{ {
ruleId = InsertRule(stmt->rulename, ruleId = InsertRule(rulename,
event_type, event_type,
ev_relid, ev_relid,
event_attno, event_attno,
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.114 2007/02/20 17:32:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.115 2007/03/13 00:33:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -36,14 +36,14 @@ static void ProcessQuery(PlannedStmt *plan, ...@@ -36,14 +36,14 @@ static void ProcessQuery(PlannedStmt *plan,
ParamListInfo params, ParamListInfo params,
DestReceiver *dest, DestReceiver *dest,
char *completionTag); char *completionTag);
static void FillPortalStore(Portal portal); static void FillPortalStore(Portal portal, bool isTopLevel);
static uint32 RunFromStore(Portal portal, ScanDirection direction, long count, static uint32 RunFromStore(Portal portal, ScanDirection direction, long count,
DestReceiver *dest); DestReceiver *dest);
static long PortalRunSelect(Portal portal, bool forward, long count, static long PortalRunSelect(Portal portal, bool forward, long count,
DestReceiver *dest); DestReceiver *dest);
static void PortalRunUtility(Portal portal, Node *utilityStmt, static void PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
DestReceiver *dest, char *completionTag); DestReceiver *dest, char *completionTag);
static void PortalRunMulti(Portal portal, static void PortalRunMulti(Portal portal, bool isTopLevel,
DestReceiver *dest, DestReceiver *altdest, DestReceiver *dest, DestReceiver *altdest,
char *completionTag); char *completionTag);
static long DoPortalRunFetch(Portal portal, static long DoPortalRunFetch(Portal portal,
...@@ -148,8 +148,7 @@ ProcessQuery(PlannedStmt *plan, ...@@ -148,8 +148,7 @@ ProcessQuery(PlannedStmt *plan,
{ {
QueryDesc *queryDesc; QueryDesc *queryDesc;
ereport(DEBUG3, elog(DEBUG3, "ProcessQuery");
(errmsg_internal("ProcessQuery")));
/* /*
* Must always set snapshot for plannable queries. Note we assume that * Must always set snapshot for plannable queries. Note we assume that
...@@ -232,8 +231,7 @@ ProcessQuery(PlannedStmt *plan, ...@@ -232,8 +231,7 @@ ProcessQuery(PlannedStmt *plan,
* Select portal execution strategy given the intended statement list. * Select portal execution strategy given the intended statement list.
* *
* The list elements can be Querys, PlannedStmts, or utility statements. * The list elements can be Querys, PlannedStmts, or utility statements.
* That's more general than portals need, but we use this for prepared * That's more general than portals need, but plancache.c uses this too.
* statements as well.
* *
* See the comments in portal.h. * See the comments in portal.h.
*/ */
...@@ -358,8 +356,7 @@ FetchPortalTargetList(Portal portal) ...@@ -358,8 +356,7 @@ FetchPortalTargetList(Portal portal)
* Returns NIL if the statement doesn't have a determinable targetlist. * Returns NIL if the statement doesn't have a determinable targetlist.
* *
* This can be applied to a Query, a PlannedStmt, or a utility statement. * This can be applied to a Query, a PlannedStmt, or a utility statement.
* That's more general than portals need, but we use this for prepared * That's more general than portals need, but plancache.c uses this too.
* statements as well.
* *
* Note: do not modify the result. * Note: do not modify the result.
* *
...@@ -452,11 +449,10 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot) ...@@ -452,11 +449,10 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
int eflags; int eflags;
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
AssertState(portal->queryContext != NULL); /* query defined? */ AssertState(portal->status == PORTAL_DEFINED);
AssertState(portal->status == PORTAL_NEW); /* else extra PortalStart */
/* /*
* Set up global portal context pointers. (Should we set QueryContext?) * Set up global portal context pointers.
*/ */
saveActivePortal = ActivePortal; saveActivePortal = ActivePortal;
saveActiveSnapshot = ActiveSnapshot; saveActiveSnapshot = ActiveSnapshot;
...@@ -683,6 +679,9 @@ PortalSetResultFormat(Portal portal, int nFormats, int16 *formats) ...@@ -683,6 +679,9 @@ PortalSetResultFormat(Portal portal, int nFormats, int16 *formats)
* interpreted as "all rows". Note that count is ignored in multi-query * interpreted as "all rows". Note that count is ignored in multi-query
* situations, where we always run the portal to completion. * situations, where we always run the portal to completion.
* *
* isTopLevel: true if query is being executed at backend "top level"
* (that is, directly from a client command message)
*
* dest: where to send output of primary (canSetTag) query * dest: where to send output of primary (canSetTag) query
* *
* altdest: where to send output of non-primary queries * altdest: where to send output of non-primary queries
...@@ -695,7 +694,7 @@ PortalSetResultFormat(Portal portal, int nFormats, int16 *formats) ...@@ -695,7 +694,7 @@ PortalSetResultFormat(Portal portal, int nFormats, int16 *formats)
* suspended due to exhaustion of the count parameter. * suspended due to exhaustion of the count parameter.
*/ */
bool bool
PortalRun(Portal portal, long count, PortalRun(Portal portal, long count, bool isTopLevel,
DestReceiver *dest, DestReceiver *altdest, DestReceiver *dest, DestReceiver *altdest,
char *completionTag) char *completionTag)
{ {
...@@ -706,7 +705,6 @@ PortalRun(Portal portal, long count, ...@@ -706,7 +705,6 @@ PortalRun(Portal portal, long count,
Snapshot saveActiveSnapshot; Snapshot saveActiveSnapshot;
ResourceOwner saveResourceOwner; ResourceOwner saveResourceOwner;
MemoryContext savePortalContext; MemoryContext savePortalContext;
MemoryContext saveQueryContext;
MemoryContext saveMemoryContext; MemoryContext saveMemoryContext;
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
...@@ -717,8 +715,7 @@ PortalRun(Portal portal, long count, ...@@ -717,8 +715,7 @@ PortalRun(Portal portal, long count,
if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY) if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY)
{ {
ereport(DEBUG3, elog(DEBUG3, "PortalRun");
(errmsg_internal("PortalRun")));
/* PORTAL_MULTI_QUERY logs its own stats per query */ /* PORTAL_MULTI_QUERY logs its own stats per query */
ResetUsage(); ResetUsage();
} }
...@@ -752,7 +749,6 @@ PortalRun(Portal portal, long count, ...@@ -752,7 +749,6 @@ PortalRun(Portal portal, long count,
saveActiveSnapshot = ActiveSnapshot; saveActiveSnapshot = ActiveSnapshot;
saveResourceOwner = CurrentResourceOwner; saveResourceOwner = CurrentResourceOwner;
savePortalContext = PortalContext; savePortalContext = PortalContext;
saveQueryContext = QueryContext;
saveMemoryContext = CurrentMemoryContext; saveMemoryContext = CurrentMemoryContext;
PG_TRY(); PG_TRY();
{ {
...@@ -760,7 +756,6 @@ PortalRun(Portal portal, long count, ...@@ -760,7 +756,6 @@ PortalRun(Portal portal, long count,
ActiveSnapshot = NULL; /* will be set later */ ActiveSnapshot = NULL; /* will be set later */
CurrentResourceOwner = portal->resowner; CurrentResourceOwner = portal->resowner;
PortalContext = PortalGetHeapMemory(portal); PortalContext = PortalGetHeapMemory(portal);
QueryContext = portal->queryContext;
MemoryContextSwitchTo(PortalContext); MemoryContextSwitchTo(PortalContext);
...@@ -790,7 +785,7 @@ PortalRun(Portal portal, long count, ...@@ -790,7 +785,7 @@ PortalRun(Portal portal, long count,
* results in the portal's tuplestore. * results in the portal's tuplestore.
*/ */
if (!portal->holdStore) if (!portal->holdStore)
FillPortalStore(portal); FillPortalStore(portal, isTopLevel);
/* /*
* Now fetch desired portion of results. * Now fetch desired portion of results.
...@@ -811,7 +806,8 @@ PortalRun(Portal portal, long count, ...@@ -811,7 +806,8 @@ PortalRun(Portal portal, long count,
break; break;
case PORTAL_MULTI_QUERY: case PORTAL_MULTI_QUERY:
PortalRunMulti(portal, dest, altdest, completionTag); PortalRunMulti(portal, isTopLevel,
dest, altdest, completionTag);
/* Prevent portal's commands from being re-executed */ /* Prevent portal's commands from being re-executed */
portal->status = PORTAL_DONE; portal->status = PORTAL_DONE;
...@@ -844,7 +840,6 @@ PortalRun(Portal portal, long count, ...@@ -844,7 +840,6 @@ PortalRun(Portal portal, long count,
else else
CurrentResourceOwner = saveResourceOwner; CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext; PortalContext = savePortalContext;
QueryContext = saveQueryContext;
PG_RE_THROW(); PG_RE_THROW();
} }
...@@ -861,7 +856,6 @@ PortalRun(Portal portal, long count, ...@@ -861,7 +856,6 @@ PortalRun(Portal portal, long count,
else else
CurrentResourceOwner = saveResourceOwner; CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext; PortalContext = savePortalContext;
QueryContext = saveQueryContext;
if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY) if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY)
ShowUsage("EXECUTOR STATISTICS"); ShowUsage("EXECUTOR STATISTICS");
...@@ -1025,7 +1019,7 @@ PortalRunSelect(Portal portal, ...@@ -1025,7 +1019,7 @@ PortalRunSelect(Portal portal,
* This is used for PORTAL_ONE_RETURNING and PORTAL_UTIL_SELECT cases only. * This is used for PORTAL_ONE_RETURNING and PORTAL_UTIL_SELECT cases only.
*/ */
static void static void
FillPortalStore(Portal portal) FillPortalStore(Portal portal, bool isTopLevel)
{ {
DestReceiver *treceiver; DestReceiver *treceiver;
char completionTag[COMPLETION_TAG_BUFSIZE]; char completionTag[COMPLETION_TAG_BUFSIZE];
...@@ -1044,12 +1038,13 @@ FillPortalStore(Portal portal) ...@@ -1044,12 +1038,13 @@ FillPortalStore(Portal portal)
* MULTI_QUERY case, but send the primary query's output to the * MULTI_QUERY case, but send the primary query's output to the
* tuplestore. Auxiliary query outputs are discarded. * tuplestore. Auxiliary query outputs are discarded.
*/ */
PortalRunMulti(portal, treceiver, None_Receiver, completionTag); PortalRunMulti(portal, isTopLevel,
treceiver, None_Receiver, completionTag);
break; break;
case PORTAL_UTIL_SELECT: case PORTAL_UTIL_SELECT:
PortalRunUtility(portal, (Node *) linitial(portal->stmts), PortalRunUtility(portal, (Node *) linitial(portal->stmts),
treceiver, completionTag); isTopLevel, treceiver, completionTag);
break; break;
default: default:
...@@ -1137,11 +1132,10 @@ RunFromStore(Portal portal, ScanDirection direction, long count, ...@@ -1137,11 +1132,10 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
* Execute a utility statement inside a portal. * Execute a utility statement inside a portal.
*/ */
static void static void
PortalRunUtility(Portal portal, Node *utilityStmt, PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
DestReceiver *dest, char *completionTag) DestReceiver *dest, char *completionTag)
{ {
ereport(DEBUG3, elog(DEBUG3, "ProcessUtility");
(errmsg_internal("ProcessUtility")));
/* /*
* Set snapshot if utility stmt needs one. Most reliable way to do this * Set snapshot if utility stmt needs one. Most reliable way to do this
...@@ -1173,7 +1167,12 @@ PortalRunUtility(Portal portal, Node *utilityStmt, ...@@ -1173,7 +1167,12 @@ PortalRunUtility(Portal portal, Node *utilityStmt,
else else
ActiveSnapshot = NULL; ActiveSnapshot = NULL;
ProcessUtility(utilityStmt, portal->portalParams, dest, completionTag); ProcessUtility(utilityStmt,
portal->sourceText,
portal->portalParams,
isTopLevel,
dest,
completionTag);
/* Some utility statements may change context on us */ /* Some utility statements may change context on us */
MemoryContextSwitchTo(PortalGetHeapMemory(portal)); MemoryContextSwitchTo(PortalGetHeapMemory(portal));
...@@ -1189,7 +1188,7 @@ PortalRunUtility(Portal portal, Node *utilityStmt, ...@@ -1189,7 +1188,7 @@ PortalRunUtility(Portal portal, Node *utilityStmt,
* or non-SELECT-like queries) * or non-SELECT-like queries)
*/ */
static void static void
PortalRunMulti(Portal portal, PortalRunMulti(Portal portal, bool isTopLevel,
DestReceiver *dest, DestReceiver *altdest, DestReceiver *dest, DestReceiver *altdest,
char *completionTag) char *completionTag)
{ {
...@@ -1260,9 +1259,9 @@ PortalRunMulti(Portal portal, ...@@ -1260,9 +1259,9 @@ PortalRunMulti(Portal portal,
* portal. * portal.
*/ */
if (list_length(portal->stmts) == 1) if (list_length(portal->stmts) == 1)
PortalRunUtility(portal, stmt, dest, completionTag); PortalRunUtility(portal, stmt, isTopLevel, dest, completionTag);
else else
PortalRunUtility(portal, stmt, altdest, NULL); PortalRunUtility(portal, stmt, isTopLevel, altdest, NULL);
} }
/* /*
...@@ -1305,6 +1304,8 @@ PortalRunMulti(Portal portal, ...@@ -1305,6 +1304,8 @@ PortalRunMulti(Portal portal,
* PortalRunFetch * PortalRunFetch
* Variant form of PortalRun that supports SQL FETCH directions. * Variant form of PortalRun that supports SQL FETCH directions.
* *
* Note: we presently assume that no callers of this want isTopLevel = true.
*
* Returns number of rows processed (suitable for use in result tag) * Returns number of rows processed (suitable for use in result tag)
*/ */
long long
...@@ -1318,7 +1319,6 @@ PortalRunFetch(Portal portal, ...@@ -1318,7 +1319,6 @@ PortalRunFetch(Portal portal,
Snapshot saveActiveSnapshot; Snapshot saveActiveSnapshot;
ResourceOwner saveResourceOwner; ResourceOwner saveResourceOwner;
MemoryContext savePortalContext; MemoryContext savePortalContext;
MemoryContext saveQueryContext;
MemoryContext oldContext; MemoryContext oldContext;
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
...@@ -1339,14 +1339,12 @@ PortalRunFetch(Portal portal, ...@@ -1339,14 +1339,12 @@ PortalRunFetch(Portal portal,
saveActiveSnapshot = ActiveSnapshot; saveActiveSnapshot = ActiveSnapshot;
saveResourceOwner = CurrentResourceOwner; saveResourceOwner = CurrentResourceOwner;
savePortalContext = PortalContext; savePortalContext = PortalContext;
saveQueryContext = QueryContext;
PG_TRY(); PG_TRY();
{ {
ActivePortal = portal; ActivePortal = portal;
ActiveSnapshot = NULL; /* will be set later */ ActiveSnapshot = NULL; /* will be set later */
CurrentResourceOwner = portal->resowner; CurrentResourceOwner = portal->resowner;
PortalContext = PortalGetHeapMemory(portal); PortalContext = PortalGetHeapMemory(portal);
QueryContext = portal->queryContext;
oldContext = MemoryContextSwitchTo(PortalContext); oldContext = MemoryContextSwitchTo(PortalContext);
...@@ -1364,7 +1362,7 @@ PortalRunFetch(Portal portal, ...@@ -1364,7 +1362,7 @@ PortalRunFetch(Portal portal,
* results in the portal's tuplestore. * results in the portal's tuplestore.
*/ */
if (!portal->holdStore) if (!portal->holdStore)
FillPortalStore(portal); FillPortalStore(portal, false /* isTopLevel */);
/* /*
* Now fetch desired portion of results. * Now fetch desired portion of results.
...@@ -1388,7 +1386,6 @@ PortalRunFetch(Portal portal, ...@@ -1388,7 +1386,6 @@ PortalRunFetch(Portal portal,
ActiveSnapshot = saveActiveSnapshot; ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner; CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext; PortalContext = savePortalContext;
QueryContext = saveQueryContext;
PG_RE_THROW(); PG_RE_THROW();
} }
...@@ -1403,7 +1400,6 @@ PortalRunFetch(Portal portal, ...@@ -1403,7 +1400,6 @@ PortalRunFetch(Portal portal,
ActiveSnapshot = saveActiveSnapshot; ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner; CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext; PortalContext = savePortalContext;
QueryContext = saveQueryContext;
return result; return result;
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.273 2007/02/20 17:32:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.274 2007/03/13 00:33:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "commands/vacuum.h" #include "commands/vacuum.h"
#include "commands/view.h" #include "commands/view.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/analyze.h"
#include "postmaster/bgwriter.h" #include "postmaster/bgwriter.h"
#include "rewrite/rewriteDefine.h" #include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h" #include "rewrite/rewriteRemove.h"
...@@ -368,7 +369,9 @@ check_xact_readonly(Node *parsetree) ...@@ -368,7 +369,9 @@ check_xact_readonly(Node *parsetree)
* general utility function invoker * general utility function invoker
* *
* parsetree: the parse tree for the utility statement * parsetree: the parse tree for the utility statement
* queryString: original source text of command (NULL if not available)
* params: parameters to use during execution * params: parameters to use during execution
* isTopLevel: true if executing a "top level" (interactively issued) command
* dest: where to send results * dest: where to send results
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
* in which to store a command completion status string. * in which to store a command completion status string.
...@@ -379,7 +382,9 @@ check_xact_readonly(Node *parsetree) ...@@ -379,7 +382,9 @@ check_xact_readonly(Node *parsetree)
*/ */
void void
ProcessUtility(Node *parsetree, ProcessUtility(Node *parsetree,
const char *queryString,
ParamListInfo params, ParamListInfo params,
bool isTopLevel,
DestReceiver *dest, DestReceiver *dest,
char *completionTag) char *completionTag)
{ {
...@@ -444,12 +449,12 @@ ProcessUtility(Node *parsetree, ...@@ -444,12 +449,12 @@ ProcessUtility(Node *parsetree,
break; break;
case TRANS_STMT_COMMIT_PREPARED: case TRANS_STMT_COMMIT_PREPARED:
PreventTransactionChain(stmt, "COMMIT PREPARED"); PreventTransactionChain(isTopLevel, "COMMIT PREPARED");
FinishPreparedTransaction(stmt->gid, true); FinishPreparedTransaction(stmt->gid, true);
break; break;
case TRANS_STMT_ROLLBACK_PREPARED: case TRANS_STMT_ROLLBACK_PREPARED:
PreventTransactionChain(stmt, "ROLLBACK PREPARED"); PreventTransactionChain(isTopLevel, "ROLLBACK PREPARED");
FinishPreparedTransaction(stmt->gid, false); FinishPreparedTransaction(stmt->gid, false);
break; break;
...@@ -462,7 +467,7 @@ ProcessUtility(Node *parsetree, ...@@ -462,7 +467,7 @@ ProcessUtility(Node *parsetree,
ListCell *cell; ListCell *cell;
char *name = NULL; char *name = NULL;
RequireTransactionChain((void *) stmt, "SAVEPOINT"); RequireTransactionChain(isTopLevel, "SAVEPOINT");
foreach(cell, stmt->options) foreach(cell, stmt->options)
{ {
...@@ -479,12 +484,12 @@ ProcessUtility(Node *parsetree, ...@@ -479,12 +484,12 @@ ProcessUtility(Node *parsetree,
break; break;
case TRANS_STMT_RELEASE: case TRANS_STMT_RELEASE:
RequireTransactionChain((void *) stmt, "RELEASE SAVEPOINT"); RequireTransactionChain(isTopLevel, "RELEASE SAVEPOINT");
ReleaseSavepoint(stmt->options); ReleaseSavepoint(stmt->options);
break; break;
case TRANS_STMT_ROLLBACK_TO: case TRANS_STMT_ROLLBACK_TO:
RequireTransactionChain((void *) stmt, "ROLLBACK TO SAVEPOINT"); RequireTransactionChain(isTopLevel, "ROLLBACK TO SAVEPOINT");
RollbackToSavepoint(stmt->options); RollbackToSavepoint(stmt->options);
/* /*
...@@ -500,7 +505,8 @@ ProcessUtility(Node *parsetree, ...@@ -500,7 +505,8 @@ ProcessUtility(Node *parsetree,
* Portal (cursor) manipulation * Portal (cursor) manipulation
*/ */
case T_DeclareCursorStmt: case T_DeclareCursorStmt:
PerformCursorOpen((DeclareCursorStmt *) parsetree, params); PerformCursorOpen((DeclareCursorStmt *) parsetree, params,
queryString, isTopLevel);
break; break;
case T_ClosePortalStmt: case T_ClosePortalStmt:
...@@ -520,7 +526,8 @@ ProcessUtility(Node *parsetree, ...@@ -520,7 +526,8 @@ ProcessUtility(Node *parsetree,
* relation and attribute manipulation * relation and attribute manipulation
*/ */
case T_CreateSchemaStmt: case T_CreateSchemaStmt:
CreateSchemaCommand((CreateSchemaStmt *) parsetree); CreateSchemaCommand((CreateSchemaStmt *) parsetree,
queryString);
break; break;
case T_CreateStmt: case T_CreateStmt:
...@@ -540,10 +547,12 @@ ProcessUtility(Node *parsetree, ...@@ -540,10 +547,12 @@ ProcessUtility(Node *parsetree,
break; break;
case T_CreateTableSpaceStmt: case T_CreateTableSpaceStmt:
PreventTransactionChain(isTopLevel, "CREATE TABLESPACE");
CreateTableSpace((CreateTableSpaceStmt *) parsetree); CreateTableSpace((CreateTableSpaceStmt *) parsetree);
break; break;
case T_DropTableSpaceStmt: case T_DropTableSpaceStmt:
PreventTransactionChain(isTopLevel, "DROP TABLESPACE");
DropTableSpace((DropTableSpaceStmt *) parsetree); DropTableSpace((DropTableSpaceStmt *) parsetree);
break; break;
...@@ -640,8 +649,9 @@ ProcessUtility(Node *parsetree, ...@@ -640,8 +649,9 @@ ProcessUtility(Node *parsetree,
case T_CopyStmt: case T_CopyStmt:
{ {
uint64 processed = DoCopy((CopyStmt *) parsetree); uint64 processed;
processed = DoCopy((CopyStmt *) parsetree, queryString);
if (completionTag) if (completionTag)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
"COPY " UINT64_FORMAT, processed); "COPY " UINT64_FORMAT, processed);
...@@ -649,11 +659,11 @@ ProcessUtility(Node *parsetree, ...@@ -649,11 +659,11 @@ ProcessUtility(Node *parsetree,
break; break;
case T_PrepareStmt: case T_PrepareStmt:
PrepareQuery((PrepareStmt *) parsetree); PrepareQuery((PrepareStmt *) parsetree, queryString);
break; break;
case T_ExecuteStmt: case T_ExecuteStmt:
ExecuteQuery((ExecuteStmt *) parsetree, params, ExecuteQuery((ExecuteStmt *) parsetree, queryString, params,
dest, completionTag); dest, completionTag);
break; break;
...@@ -769,12 +779,8 @@ ProcessUtility(Node *parsetree, ...@@ -769,12 +779,8 @@ ProcessUtility(Node *parsetree,
} }
break; break;
case T_ViewStmt: /* CREATE VIEW */ case T_ViewStmt: /* CREATE VIEW */
{ DefineView((ViewStmt *) parsetree, queryString);
ViewStmt *stmt = (ViewStmt *) parsetree;
DefineView(stmt->view, stmt->query, stmt->replace);
}
break; break;
case T_CreateFunctionStmt: /* CREATE FUNCTION */ case T_CreateFunctionStmt: /* CREATE FUNCTION */
...@@ -790,10 +796,15 @@ ProcessUtility(Node *parsetree, ...@@ -790,10 +796,15 @@ ProcessUtility(Node *parsetree,
IndexStmt *stmt = (IndexStmt *) parsetree; IndexStmt *stmt = (IndexStmt *) parsetree;
if (stmt->concurrent) if (stmt->concurrent)
PreventTransactionChain(stmt, "CREATE INDEX CONCURRENTLY"); PreventTransactionChain(isTopLevel,
"CREATE INDEX CONCURRENTLY");
CheckRelationOwnership(stmt->relation, true); CheckRelationOwnership(stmt->relation, true);
/* Run parse analysis ... */
stmt = analyzeIndexStmt(stmt, queryString);
/* ... and do it */
DefineIndex(stmt->relation, /* relation */ DefineIndex(stmt->relation, /* relation */
stmt->idxname, /* index name */ stmt->idxname, /* index name */
InvalidOid, /* no predefined OID */ InvalidOid, /* no predefined OID */
...@@ -801,7 +812,6 @@ ProcessUtility(Node *parsetree, ...@@ -801,7 +812,6 @@ ProcessUtility(Node *parsetree,
stmt->tableSpace, stmt->tableSpace,
stmt->indexParams, /* parameters */ stmt->indexParams, /* parameters */
(Expr *) stmt->whereClause, (Expr *) stmt->whereClause,
stmt->rangetable,
stmt->options, stmt->options,
stmt->unique, stmt->unique,
stmt->primary, stmt->primary,
...@@ -815,7 +825,7 @@ ProcessUtility(Node *parsetree, ...@@ -815,7 +825,7 @@ ProcessUtility(Node *parsetree,
break; break;
case T_RuleStmt: /* CREATE RULE */ case T_RuleStmt: /* CREATE RULE */
DefineQueryRewrite((RuleStmt *) parsetree); DefineRule((RuleStmt *) parsetree, queryString);
break; break;
case T_CreateSeqStmt: case T_CreateSeqStmt:
...@@ -850,6 +860,7 @@ ProcessUtility(Node *parsetree, ...@@ -850,6 +860,7 @@ ProcessUtility(Node *parsetree,
break; break;
case T_CreatedbStmt: case T_CreatedbStmt:
PreventTransactionChain(isTopLevel, "CREATE DATABASE");
createdb((CreatedbStmt *) parsetree); createdb((CreatedbStmt *) parsetree);
break; break;
...@@ -865,6 +876,7 @@ ProcessUtility(Node *parsetree, ...@@ -865,6 +876,7 @@ ProcessUtility(Node *parsetree,
{ {
DropdbStmt *stmt = (DropdbStmt *) parsetree; DropdbStmt *stmt = (DropdbStmt *) parsetree;
PreventTransactionChain(isTopLevel, "DROP DATABASE");
dropdb(stmt->dbname, stmt->missing_ok); dropdb(stmt->dbname, stmt->missing_ok);
} }
break; break;
...@@ -905,15 +917,15 @@ ProcessUtility(Node *parsetree, ...@@ -905,15 +917,15 @@ ProcessUtility(Node *parsetree,
break; break;
case T_ClusterStmt: case T_ClusterStmt:
cluster((ClusterStmt *) parsetree); cluster((ClusterStmt *) parsetree, isTopLevel);
break; break;
case T_VacuumStmt: case T_VacuumStmt:
vacuum((VacuumStmt *) parsetree, NIL); vacuum((VacuumStmt *) parsetree, NIL, isTopLevel);
break; break;
case T_ExplainStmt: case T_ExplainStmt:
ExplainQuery((ExplainStmt *) parsetree, params, dest); ExplainQuery((ExplainStmt *) parsetree, queryString, params, dest);
break; break;
case T_VariableSetStmt: case T_VariableSetStmt:
...@@ -1079,6 +1091,14 @@ ProcessUtility(Node *parsetree, ...@@ -1079,6 +1091,14 @@ ProcessUtility(Node *parsetree,
ReindexTable(stmt->relation); ReindexTable(stmt->relation);
break; break;
case OBJECT_DATABASE: case OBJECT_DATABASE:
/*
* This cannot run inside a user transaction block;
* if we were inside a transaction, then its commit-
* and start-transaction-command calls would not have
* the intended effect!
*/
PreventTransactionChain(isTopLevel,
"REINDEX DATABASE");
ReindexDatabase(stmt->name, ReindexDatabase(stmt->name,
stmt->do_system, stmt->do_user); stmt->do_system, stmt->do_user);
break; break;
...@@ -1166,16 +1186,8 @@ UtilityReturnsTuples(Node *parsetree) ...@@ -1166,16 +1186,8 @@ UtilityReturnsTuples(Node *parsetree)
entry = FetchPreparedStatement(stmt->name, false); entry = FetchPreparedStatement(stmt->name, false);
if (!entry) if (!entry)
return false; /* not our business to raise error */ return false; /* not our business to raise error */
switch (ChoosePortalStrategy(entry->stmt_list)) if (entry->plansource->resultDesc)
{ return true;
case PORTAL_ONE_SELECT:
case PORTAL_ONE_RETURNING:
case PORTAL_UTIL_SELECT:
return true;
case PORTAL_MULTI_QUERY:
/* will not return tuples */
break;
}
return false; return false;
} }
...@@ -2134,7 +2146,7 @@ GetCommandLogLevel(Node *parsetree) ...@@ -2134,7 +2146,7 @@ GetCommandLogLevel(Node *parsetree)
/* Look through an EXPLAIN ANALYZE to the contained stmt */ /* Look through an EXPLAIN ANALYZE to the contained stmt */
if (stmt->analyze) if (stmt->analyze)
return GetCommandLogLevel((Node *) stmt->query); return GetCommandLogLevel(stmt->query);
/* Plain EXPLAIN isn't so interesting */ /* Plain EXPLAIN isn't so interesting */
lev = LOGSTMT_ALL; lev = LOGSTMT_ALL;
} }
...@@ -2245,30 +2257,21 @@ GetCommandLogLevel(Node *parsetree) ...@@ -2245,30 +2257,21 @@ GetCommandLogLevel(Node *parsetree)
PrepareStmt *stmt = (PrepareStmt *) parsetree; PrepareStmt *stmt = (PrepareStmt *) parsetree;
/* Look through a PREPARE to the contained stmt */ /* Look through a PREPARE to the contained stmt */
return GetCommandLogLevel((Node *) stmt->query); lev = GetCommandLogLevel(stmt->query);
} }
break; break;
case T_ExecuteStmt: case T_ExecuteStmt:
{ {
ExecuteStmt *stmt = (ExecuteStmt *) parsetree; ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
PreparedStatement *pstmt; PreparedStatement *ps;
ListCell *l;
/* Look through an EXECUTE to the referenced stmt(s) */
lev = LOGSTMT_ALL;
pstmt = FetchPreparedStatement(stmt->name, false);
if (pstmt)
{
foreach(l, pstmt->stmt_list)
{
Node *substmt = (Node *) lfirst(l);
LogStmtLevel stmt_lev;
stmt_lev = GetCommandLogLevel(substmt); /* Look through an EXECUTE to the referenced stmt */
lev = Min(lev, stmt_lev); ps = FetchPreparedStatement(stmt->name, false);
} if (ps)
} lev = GetCommandLogLevel(ps->plansource->raw_parse_tree);
else
lev = LOGSTMT_ALL;
} }
break; break;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# Makefile for utils/cache # Makefile for utils/cache
# #
# IDENTIFICATION # IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/utils/cache/Makefile,v 1.20 2007/01/20 17:16:13 petere Exp $ # $PostgreSQL: pgsql/src/backend/utils/cache/Makefile,v 1.21 2007/03/13 00:33:42 tgl Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -12,7 +12,8 @@ subdir = src/backend/utils/cache ...@@ -12,7 +12,8 @@ subdir = src/backend/utils/cache
top_builddir = ../../../.. top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global include $(top_builddir)/src/Makefile.global
OBJS = catcache.o inval.o relcache.o syscache.o lsyscache.o typcache.o OBJS = catcache.o inval.o plancache.o relcache.o \
syscache.o lsyscache.o typcache.o
all: SUBSYS.o all: SUBSYS.o
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.174 2007/02/15 23:23:23 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.175 2007/03/13 00:33:42 tgl Exp $
* *
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "libpq/hba.h" #include "libpq/hba.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h" #include "postmaster/autovacuum.h"
#include "postmaster/postmaster.h" #include "postmaster/postmaster.h"
#include "storage/backendid.h" #include "storage/backendid.h"
...@@ -40,10 +41,10 @@ ...@@ -40,10 +41,10 @@
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/flatfiles.h" #include "utils/flatfiles.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/plancache.h"
#include "utils/portal.h" #include "utils/portal.h"
#include "utils/relcache.h" #include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "pgstat.h"
static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace); static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace);
...@@ -429,6 +430,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, ...@@ -429,6 +430,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
*/ */
RelationCacheInitialize(); RelationCacheInitialize();
InitCatalogCache(); InitCatalogCache();
InitPlanCache();
/* Initialize portal manager */ /* Initialize portal manager */
EnablePortalManager(); EnablePortalManager();
......
$PostgreSQL: pgsql/src/backend/utils/mmgr/README,v 1.9 2006/09/07 22:52:01 tgl Exp $ $PostgreSQL: pgsql/src/backend/utils/mmgr/README,v 1.10 2007/03/13 00:33:42 tgl Exp $
Notes about memory allocation redesign Notes about memory allocation redesign
-------------------------------------- --------------------------------------
...@@ -201,15 +201,6 @@ have dangling pointers leading to a crash at top-level commit. An example of ...@@ -201,15 +201,6 @@ have dangling pointers leading to a crash at top-level commit. An example of
data kept here is pending NOTIFY messages, which are sent at top-level commit, data kept here is pending NOTIFY messages, which are sent at top-level commit,
but only if the generating subtransaction did not abort. but only if the generating subtransaction did not abort.
QueryContext --- this is not actually a separate context, but a global
variable pointing to the context that holds the current command's parse tree.
(In simple-Query mode this points to MessageContext; when executing a
prepared statement it will point to the prepared statement's private context.
Note that the plan tree may or may not be in this same context.)
Generally it is not appropriate for any code to use QueryContext as an
allocation target --- from the point of view of any code that would be
referencing the QueryContext variable, it's a read-only context.
PortalContext --- this is not actually a separate context either, but a PortalContext --- this is not actually a separate context either, but a
global variable pointing to the per-portal context of the currently active global variable pointing to the per-portal context of the currently active
execution portal. This can be used if it's necessary to allocate storage execution portal. This can be used if it's necessary to allocate storage
...@@ -229,9 +220,7 @@ Contexts for prepared statements and portals ...@@ -229,9 +220,7 @@ Contexts for prepared statements and portals
A prepared-statement object has an associated private context, in which A prepared-statement object has an associated private context, in which
the parse and plan trees for its query are stored. Because these trees the parse and plan trees for its query are stored. Because these trees
are read-only to the executor, the prepared statement can be re-used many are read-only to the executor, the prepared statement can be re-used many
times without further copying of these trees. QueryContext points at this times without further copying of these trees.
private context while executing any portal built from the prepared
statement.
An execution-portal object has a private context that is referenced by An execution-portal object has a private context that is referenced by
PortalContext when the portal is active. In the case of a portal created PortalContext when the portal is active. In the case of a portal created
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/mmgr/mcxt.c,v 1.59 2007/01/05 22:19:47 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/mmgr/mcxt.c,v 1.60 2007/03/13 00:33:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -46,8 +46,7 @@ MemoryContext MessageContext = NULL; ...@@ -46,8 +46,7 @@ MemoryContext MessageContext = NULL;
MemoryContext TopTransactionContext = NULL; MemoryContext TopTransactionContext = NULL;
MemoryContext CurTransactionContext = NULL; MemoryContext CurTransactionContext = NULL;
/* These two are transient links to contexts owned by other objects: */ /* This is a transient link to the active portal's memory context: */
MemoryContext QueryContext = NULL;
MemoryContext PortalContext = NULL; MemoryContext PortalContext = NULL;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.99 2007/02/20 17:32:17 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.100 2007/03/13 00:33:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -149,9 +149,9 @@ GetPortalByName(const char *name) ...@@ -149,9 +149,9 @@ GetPortalByName(const char *name)
* cases should occur in present usages of this function. * cases should occur in present usages of this function.
* *
* Copes if given a list of Querys --- can't happen in a portal, but this * Copes if given a list of Querys --- can't happen in a portal, but this
* code also supports prepared statements, which need both cases. * code also supports plancache.c, which needs both cases.
* *
* Note: the reason this is just handed a List is so that prepared statements * Note: the reason this is just handed a List is so that plancache.c
* can share the code. For use with a portal, use PortalGetPrimaryStmt * can share the code. For use with a portal, use PortalGetPrimaryStmt
* rather than calling this directly. * rather than calling this directly.
*/ */
...@@ -275,9 +275,17 @@ CreateNewPortal(void) ...@@ -275,9 +275,17 @@ CreateNewPortal(void)
* *
* Notes: commandTag shall be NULL if and only if the original query string * Notes: commandTag shall be NULL if and only if the original query string
* (before rewriting) was an empty string. Also, the passed commandTag must * (before rewriting) was an empty string. Also, the passed commandTag must
* be a pointer to a constant string, since it is not copied. The caller is * be a pointer to a constant string, since it is not copied. However,
* responsible for ensuring that the passed prepStmtName (if any), sourceText * prepStmtName and sourceText, if provided, are copied into the portal's
* (if any), and plan trees have adequate lifetime. * heap context for safekeeping.
*
* If cplan is provided, then it is a cached plan containing the stmts,
* and the caller must have done RevalidateCachedPlan(), causing a refcount
* increment. The refcount will be released when the portal is destroyed.
*
* If cplan is NULL, then it is the caller's responsibility to ensure that
* the passed plan trees have adequate lifetime. Typically this is done by
* copying them into the portal's heap context.
*/ */
void void
PortalDefineQuery(Portal portal, PortalDefineQuery(Portal portal,
...@@ -285,18 +293,35 @@ PortalDefineQuery(Portal portal, ...@@ -285,18 +293,35 @@ PortalDefineQuery(Portal portal,
const char *sourceText, const char *sourceText,
const char *commandTag, const char *commandTag,
List *stmts, List *stmts,
MemoryContext queryContext) CachedPlan *cplan)
{ {
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
AssertState(portal->queryContext == NULL); /* else defined already */ AssertState(portal->status == PORTAL_NEW);
Assert(commandTag != NULL || stmts == NIL); Assert(commandTag != NULL || stmts == NIL);
portal->prepStmtName = prepStmtName; portal->prepStmtName = prepStmtName ?
portal->sourceText = sourceText; MemoryContextStrdup(PortalGetHeapMemory(portal), prepStmtName) : NULL;
portal->sourceText = sourceText ?
MemoryContextStrdup(PortalGetHeapMemory(portal), sourceText) : NULL;
portal->commandTag = commandTag; portal->commandTag = commandTag;
portal->stmts = stmts; portal->stmts = stmts;
portal->queryContext = queryContext; portal->cplan = cplan;
portal->status = PORTAL_DEFINED;
}
/*
* PortalReleaseCachedPlan
* Release a portal's reference to its cached plan, if any.
*/
static void
PortalReleaseCachedPlan(Portal portal)
{
if (portal->cplan)
{
ReleaseCachedPlan(portal->cplan, false);
portal->cplan = NULL;
}
} }
/* /*
...@@ -356,6 +381,10 @@ PortalDrop(Portal portal, bool isTopCommit) ...@@ -356,6 +381,10 @@ PortalDrop(Portal portal, bool isTopCommit)
if (PointerIsValid(portal->cleanup)) if (PointerIsValid(portal->cleanup))
(*portal->cleanup) (portal); (*portal->cleanup) (portal);
/* drop cached plan reference, if any */
if (portal->cplan)
PortalReleaseCachedPlan(portal);
/* /*
* Release any resources still attached to the portal. There are several * Release any resources still attached to the portal. There are several
* cases being covered here: * cases being covered here:
...@@ -423,29 +452,6 @@ PortalDrop(Portal portal, bool isTopCommit) ...@@ -423,29 +452,6 @@ PortalDrop(Portal portal, bool isTopCommit)
pfree(portal); pfree(portal);
} }
/*
* DropDependentPortals
* Drop any portals using the specified context as queryContext.
*
* This is normally used to make sure we can safely drop a prepared statement.
*/
void
DropDependentPortals(MemoryContext queryContext)
{
HASH_SEQ_STATUS status;
PortalHashEnt *hentry;
hash_seq_init(&status, PortalHashTable);
while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
{
Portal portal = hentry->portal;
if (portal->queryContext == queryContext)
PortalDrop(portal, false);
}
}
/* /*
* Pre-commit processing for portals. * Pre-commit processing for portals.
...@@ -485,6 +491,10 @@ CommitHoldablePortals(void) ...@@ -485,6 +491,10 @@ CommitHoldablePortals(void)
PortalCreateHoldStore(portal); PortalCreateHoldStore(portal);
PersistHoldablePortal(portal); PersistHoldablePortal(portal);
/* drop cached plan reference, if any */
if (portal->cplan)
PortalReleaseCachedPlan(portal);
/* /*
* Any resources belonging to the portal will be released in the * Any resources belonging to the portal will be released in the
* upcoming transaction-wide cleanup; the portal will no longer * upcoming transaction-wide cleanup; the portal will no longer
...@@ -630,6 +640,10 @@ AtAbort_Portals(void) ...@@ -630,6 +640,10 @@ AtAbort_Portals(void)
portal->cleanup = NULL; portal->cleanup = NULL;
} }
/* drop cached plan reference, if any */
if (portal->cplan)
PortalReleaseCachedPlan(portal);
/* /*
* Any resources belonging to the portal will be released in the * Any resources belonging to the portal will be released in the
* upcoming transaction-wide cleanup; they will be gone before we run * upcoming transaction-wide cleanup; they will be gone before we run
...@@ -769,6 +783,10 @@ AtSubAbort_Portals(SubTransactionId mySubid, ...@@ -769,6 +783,10 @@ AtSubAbort_Portals(SubTransactionId mySubid,
portal->cleanup = NULL; portal->cleanup = NULL;
} }
/* drop cached plan reference, if any */
if (portal->cplan)
PortalReleaseCachedPlan(portal);
/* /*
* Any resources belonging to the portal will be released in the * Any resources belonging to the portal will be released in the
* upcoming transaction-wide cleanup; they will be gone before we * upcoming transaction-wide cleanup; they will be gone before we
......
$PostgreSQL: pgsql/src/backend/utils/resowner/README,v 1.4 2006/06/16 18:42:23 tgl Exp $ $PostgreSQL: pgsql/src/backend/utils/resowner/README,v 1.5 2007/03/13 00:33:42 tgl Exp $
Notes about resource owners Notes about resource owners
--------------------------- ---------------------------
...@@ -60,12 +60,13 @@ subtransaction or portal. Therefore, the "release" operation on a child ...@@ -60,12 +60,13 @@ subtransaction or portal. Therefore, the "release" operation on a child
ResourceOwner transfers lock ownership to the parent instead of actually ResourceOwner transfers lock ownership to the parent instead of actually
releasing the lock, if isCommit is true. releasing the lock, if isCommit is true.
Currently, ResourceOwners contain direct support for recording ownership Currently, ResourceOwners contain direct support for recording ownership of
of buffer pins, lmgr locks, and catcache, relcache, and tupdesc references. buffer pins, lmgr locks, and catcache, relcache, plancache, and tupdesc
Other objects can be associated with a ResourceOwner by recording the address references. Other objects can be associated with a ResourceOwner by recording
of the owning ResourceOwner in such an object. There is an API for other the address of the owning ResourceOwner in such an object. There is an API
modules to get control during ResourceOwner release, so that they can scan for other modules to get control during ResourceOwner release, so that they
their own data structures to find the objects that need to be deleted. can scan their own data structures to find the objects that need to be
deleted.
Whenever we are inside a transaction, the global variable Whenever we are inside a transaction, the global variable
CurrentResourceOwner shows which resource owner should be assigned CurrentResourceOwner shows which resource owner should be assigned
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.23 2007/01/05 22:19:47 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.24 2007/03/13 00:33:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -56,6 +56,11 @@ typedef struct ResourceOwnerData ...@@ -56,6 +56,11 @@ typedef struct ResourceOwnerData
Relation *relrefs; /* dynamically allocated array */ Relation *relrefs; /* dynamically allocated array */
int maxrelrefs; /* currently allocated array size */ int maxrelrefs; /* currently allocated array size */
/* We have built-in support for remembering plancache references */
int nplanrefs; /* number of owned plancache pins */
CachedPlan **planrefs; /* dynamically allocated array */
int maxplanrefs; /* currently allocated array size */
/* We have built-in support for remembering tupdesc references */ /* We have built-in support for remembering tupdesc references */
int ntupdescs; /* number of owned tupdesc references */ int ntupdescs; /* number of owned tupdesc references */
TupleDesc *tupdescs; /* dynamically allocated array */ TupleDesc *tupdescs; /* dynamically allocated array */
...@@ -90,6 +95,7 @@ static void ResourceOwnerReleaseInternal(ResourceOwner owner, ...@@ -90,6 +95,7 @@ static void ResourceOwnerReleaseInternal(ResourceOwner owner,
bool isCommit, bool isCommit,
bool isTopLevel); bool isTopLevel);
static void PrintRelCacheLeakWarning(Relation rel); static void PrintRelCacheLeakWarning(Relation rel);
static void PrintPlanCacheLeakWarning(CachedPlan *plan);
static void PrintTupleDescLeakWarning(TupleDesc tupdesc); static void PrintTupleDescLeakWarning(TupleDesc tupdesc);
...@@ -280,6 +286,13 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, ...@@ -280,6 +286,13 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
PrintCatCacheListLeakWarning(owner->catlistrefs[owner->ncatlistrefs - 1]); PrintCatCacheListLeakWarning(owner->catlistrefs[owner->ncatlistrefs - 1]);
ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]); ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]);
} }
/* Ditto for plancache references */
while (owner->nplanrefs > 0)
{
if (isCommit)
PrintPlanCacheLeakWarning(owner->planrefs[owner->nplanrefs - 1]);
ReleaseCachedPlan(owner->planrefs[owner->nplanrefs - 1], true);
}
/* Ditto for tupdesc references */ /* Ditto for tupdesc references */
while (owner->ntupdescs > 0) while (owner->ntupdescs > 0)
{ {
...@@ -316,6 +329,7 @@ ResourceOwnerDelete(ResourceOwner owner) ...@@ -316,6 +329,7 @@ ResourceOwnerDelete(ResourceOwner owner)
Assert(owner->ncatrefs == 0); Assert(owner->ncatrefs == 0);
Assert(owner->ncatlistrefs == 0); Assert(owner->ncatlistrefs == 0);
Assert(owner->nrelrefs == 0); Assert(owner->nrelrefs == 0);
Assert(owner->nplanrefs == 0);
Assert(owner->ntupdescs == 0); Assert(owner->ntupdescs == 0);
/* /*
...@@ -341,6 +355,8 @@ ResourceOwnerDelete(ResourceOwner owner) ...@@ -341,6 +355,8 @@ ResourceOwnerDelete(ResourceOwner owner)
pfree(owner->catlistrefs); pfree(owner->catlistrefs);
if (owner->relrefs) if (owner->relrefs)
pfree(owner->relrefs); pfree(owner->relrefs);
if (owner->planrefs)
pfree(owner->planrefs);
if (owner->tupdescs) if (owner->tupdescs)
pfree(owner->tupdescs); pfree(owner->tupdescs);
...@@ -758,6 +774,86 @@ PrintRelCacheLeakWarning(Relation rel) ...@@ -758,6 +774,86 @@ PrintRelCacheLeakWarning(Relation rel)
RelationGetRelationName(rel)); RelationGetRelationName(rel));
} }
/*
* Make sure there is room for at least one more entry in a ResourceOwner's
* plancache reference array.
*
* This is separate from actually inserting an entry because if we run out
* of memory, it's critical to do so *before* acquiring the resource.
*/
void
ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
{
int newmax;
if (owner->nplanrefs < owner->maxplanrefs)
return; /* nothing to do */
if (owner->planrefs == NULL)
{
newmax = 16;
owner->planrefs = (CachedPlan **)
MemoryContextAlloc(TopMemoryContext, newmax * sizeof(CachedPlan *));
owner->maxplanrefs = newmax;
}
else
{
newmax = owner->maxplanrefs * 2;
owner->planrefs = (CachedPlan **)
repalloc(owner->planrefs, newmax * sizeof(CachedPlan *));
owner->maxplanrefs = newmax;
}
}
/*
* Remember that a plancache reference is owned by a ResourceOwner
*
* Caller must have previously done ResourceOwnerEnlargePlanCacheRefs()
*/
void
ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
{
Assert(owner->nplanrefs < owner->maxplanrefs);
owner->planrefs[owner->nplanrefs] = plan;
owner->nplanrefs++;
}
/*
* Forget that a plancache reference is owned by a ResourceOwner
*/
void
ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
{
CachedPlan **planrefs = owner->planrefs;
int np1 = owner->nplanrefs - 1;
int i;
for (i = np1; i >= 0; i--)
{
if (planrefs[i] == plan)
{
while (i < np1)
{
planrefs[i] = planrefs[i + 1];
i++;
}
owner->nplanrefs = np1;
return;
}
}
elog(ERROR, "plancache reference %p is not owned by resource owner %s",
plan, owner->name);
}
/*
* Debugging subroutine
*/
static void
PrintPlanCacheLeakWarning(CachedPlan *plan)
{
elog(WARNING, "plancache reference leak: plan %p not closed", plan);
}
/* /*
* Make sure there is room for at least one more entry in a ResourceOwner's * Make sure there is room for at least one more entry in a ResourceOwner's
* tupdesc reference array. * tupdesc reference array.
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/xact.h,v 1.84 2007/01/05 22:19:51 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.85 2007/03/13 00:33:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -164,9 +164,9 @@ extern bool IsTransactionBlock(void); ...@@ -164,9 +164,9 @@ extern bool IsTransactionBlock(void);
extern bool IsTransactionOrTransactionBlock(void); extern bool IsTransactionOrTransactionBlock(void);
extern char TransactionBlockStatusCode(void); extern char TransactionBlockStatusCode(void);
extern void AbortOutOfAnyTransaction(void); extern void AbortOutOfAnyTransaction(void);
extern void PreventTransactionChain(void *stmtNode, const char *stmtType); extern void PreventTransactionChain(bool isTopLevel, const char *stmtType);
extern void RequireTransactionChain(void *stmtNode, const char *stmtType); extern void RequireTransactionChain(bool isTopLevel, const char *stmtType);
extern bool IsInTransactionChain(void *stmtNode); extern bool IsInTransactionChain(bool isTopLevel);
extern void RegisterXactCallback(XactCallback callback, void *arg); extern void RegisterXactCallback(XactCallback callback, void *arg);
extern void UnregisterXactCallback(XactCallback callback, void *arg); extern void UnregisterXactCallback(XactCallback callback, void *arg);
extern void RegisterSubXactCallback(SubXactCallback callback, void *arg); extern void RegisterSubXactCallback(SubXactCallback callback, void *arg);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/cluster.h,v 1.31 2007/01/05 22:19:53 momjian Exp $ * $PostgreSQL: pgsql/src/include/commands/cluster.h,v 1.32 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include "utils/rel.h" #include "utils/rel.h"
extern void cluster(ClusterStmt *stmt); extern void cluster(ClusterStmt *stmt, bool isTopLevel);
extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid, extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
bool recheck); bool recheck);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/copy.h,v 1.29 2007/01/05 22:19:53 momjian Exp $ * $PostgreSQL: pgsql/src/include/commands/copy.h,v 1.30 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include "tcop/dest.h" #include "tcop/dest.h"
extern uint64 DoCopy(const CopyStmt *stmt); extern uint64 DoCopy(const CopyStmt *stmt, const char *queryString);
extern DestReceiver *CreateCopyDestReceiver(void); extern DestReceiver *CreateCopyDestReceiver(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.80 2007/01/23 05:07:18 tgl Exp $ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.81 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -25,7 +25,6 @@ extern void DefineIndex(RangeVar *heapRelation, ...@@ -25,7 +25,6 @@ extern void DefineIndex(RangeVar *heapRelation,
char *tableSpaceName, char *tableSpaceName,
List *attributeList, List *attributeList,
Expr *predicate, Expr *predicate,
List *rangetable,
List *options, List *options,
bool unique, bool unique,
bool primary, bool primary,
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/explain.h,v 1.29 2007/01/05 22:19:53 momjian Exp $ * $PostgreSQL: pgsql/src/include/commands/explain.h,v 1.30 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,11 +16,16 @@ ...@@ -16,11 +16,16 @@
#include "executor/executor.h" #include "executor/executor.h"
extern void ExplainQuery(ExplainStmt *stmt, ParamListInfo params, extern void ExplainQuery(ExplainStmt *stmt, const char *queryString,
DestReceiver *dest); ParamListInfo params, DestReceiver *dest);
extern TupleDesc ExplainResultDesc(ExplainStmt *stmt); extern TupleDesc ExplainResultDesc(ExplainStmt *stmt);
extern void ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
const char *queryString,
ParamListInfo params,
TupOutputState *tstate);
extern void ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt, extern void ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
TupOutputState *tstate); TupOutputState *tstate);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/portalcmds.h,v 1.21 2007/02/20 17:32:17 tgl Exp $ * $PostgreSQL: pgsql/src/include/commands/portalcmds.h,v 1.22 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
#include "utils/portal.h" #include "utils/portal.h"
extern void PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params); extern void PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params,
const char *queryString, bool isTopLevel);
extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest, extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest,
char *completionTag); char *completionTag);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 2002-2007, PostgreSQL Global Development Group * Copyright (c) 2002-2007, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.24 2007/02/20 17:32:17 tgl Exp $ * $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.25 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -14,58 +14,49 @@ ...@@ -14,58 +14,49 @@
#define PREPARE_H #define PREPARE_H
#include "executor/executor.h" #include "executor/executor.h"
#include "utils/plancache.h"
#include "utils/timestamp.h" #include "utils/timestamp.h"
/* /*
* The data structure representing a prepared statement * The data structure representing a prepared statement. This is now just
* a thin veneer over a plancache entry --- the main addition is that of
* a name.
* *
* A prepared statement might be fully planned, or only parsed-and-rewritten. * Note: all subsidiary storage lives in the referenced plancache entry.
* If fully planned, stmt_list contains PlannedStmts and/or utility statements;
* if not, it contains Query nodes.
*
* Note: all subsidiary storage lives in the context denoted by the context
* field. However, the string referenced by commandTag is not subsidiary
* storage; it is assumed to be a compile-time-constant string. As with
* portals, commandTag shall be NULL if and only if the original query string
* (before rewriting) was an empty string.
*/ */
typedef struct typedef struct
{ {
/* dynahash.c requires key to be first field */ /* dynahash.c requires key to be first field */
char stmt_name[NAMEDATALEN]; char stmt_name[NAMEDATALEN];
char *query_string; /* text of query, or NULL */ CachedPlanSource *plansource; /* the actual cached plan */
const char *commandTag; /* command tag (a constant!), or NULL */
List *stmt_list; /* list of statement or Query nodes */
List *argtype_list; /* list of parameter type OIDs */
bool fully_planned; /* what is in stmt_list, exactly? */
bool from_sql; /* prepared via SQL, not FE/BE protocol? */ bool from_sql; /* prepared via SQL, not FE/BE protocol? */
TimestampTz prepare_time; /* the time when the stmt was prepared */ TimestampTz prepare_time; /* the time when the stmt was prepared */
MemoryContext context; /* context containing this query */
} PreparedStatement; } PreparedStatement;
/* Utility statements PREPARE, EXECUTE, DEALLOCATE, EXPLAIN EXECUTE */ /* Utility statements PREPARE, EXECUTE, DEALLOCATE, EXPLAIN EXECUTE */
extern void PrepareQuery(PrepareStmt *stmt); extern void PrepareQuery(PrepareStmt *stmt, const char *queryString);
extern void ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params, extern void ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
ParamListInfo params,
DestReceiver *dest, char *completionTag); DestReceiver *dest, char *completionTag);
extern void DeallocateQuery(DeallocateStmt *stmt); extern void DeallocateQuery(DeallocateStmt *stmt);
extern void ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params, extern void ExplainExecuteQuery(ExecuteStmt *execstmt, ExplainStmt *stmt,
TupOutputState *tstate); const char *queryString,
ParamListInfo params, TupOutputState *tstate);
/* Low-level access to stored prepared statements */ /* Low-level access to stored prepared statements */
extern void StorePreparedStatement(const char *stmt_name, extern void StorePreparedStatement(const char *stmt_name,
Node *raw_parse_tree,
const char *query_string, const char *query_string,
const char *commandTag, const char *commandTag,
Oid *param_types,
int num_params,
List *stmt_list, List *stmt_list,
List *argtype_list,
bool fully_planned,
bool from_sql); bool from_sql);
extern PreparedStatement *FetchPreparedStatement(const char *stmt_name, extern PreparedStatement *FetchPreparedStatement(const char *stmt_name,
bool throwError); bool throwError);
extern void DropPreparedStatement(const char *stmt_name, bool showError); extern void DropPreparedStatement(const char *stmt_name, bool showError);
extern List *FetchPreparedStatementParams(const char *stmt_name);
extern TupleDesc FetchPreparedStatementResultDesc(PreparedStatement *stmt); extern TupleDesc FetchPreparedStatementResultDesc(PreparedStatement *stmt);
extern bool PreparedStatementReturnsTuples(PreparedStatement *stmt);
extern List *FetchPreparedStatementTargetList(PreparedStatement *stmt); extern List *FetchPreparedStatementTargetList(PreparedStatement *stmt);
#endif /* PREPARE_H */ #endif /* PREPARE_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/schemacmds.h,v 1.15 2007/01/05 22:19:54 momjian Exp $ * $PostgreSQL: pgsql/src/include/commands/schemacmds.h,v 1.16 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
extern void CreateSchemaCommand(CreateSchemaStmt *parsetree); extern void CreateSchemaCommand(CreateSchemaStmt *parsetree,
const char *queryString);
extern void RemoveSchema(List *names, DropBehavior behavior, bool missing_ok); extern void RemoveSchema(List *names, DropBehavior behavior, bool missing_ok);
extern void RemoveSchemaById(Oid schemaOid); extern void RemoveSchemaById(Oid schemaOid);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.69 2007/01/05 22:19:54 momjian Exp $ * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.70 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -110,7 +110,7 @@ extern int vacuum_freeze_min_age; ...@@ -110,7 +110,7 @@ extern int vacuum_freeze_min_age;
/* in commands/vacuum.c */ /* in commands/vacuum.c */
extern void vacuum(VacuumStmt *vacstmt, List *relids); extern void vacuum(VacuumStmt *vacstmt, List *relids, bool isTopLevel);
extern void vac_open_indexes(Relation relation, LOCKMODE lockmode, extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
int *nindexes, Relation **Irel); int *nindexes, Relation **Irel);
extern void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode); extern void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/view.h,v 1.24 2007/01/05 22:19:54 momjian Exp $ * $PostgreSQL: pgsql/src/include/commands/view.h,v 1.25 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
extern void DefineView(RangeVar *view, Query *view_parse, bool replace); extern void DefineView(ViewStmt *stmt, const char *queryString);
extern void RemoveView(const RangeVar *view, DropBehavior behavior); extern void RemoveView(const RangeVar *view, DropBehavior behavior);
#endif /* VIEW_H */ #endif /* VIEW_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/params.h,v 1.34 2007/01/05 22:19:55 momjian Exp $ * $PostgreSQL: pgsql/src/include/nodes/params.h,v 1.35 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -82,4 +82,7 @@ typedef struct ParamExecData ...@@ -82,4 +82,7 @@ typedef struct ParamExecData
/* Functions found in src/backend/nodes/params.c */ /* Functions found in src/backend/nodes/params.c */
extern ParamListInfo copyParamList(ParamListInfo from); extern ParamListInfo copyParamList(ParamListInfo from);
extern void getParamListTypes(ParamListInfo params,
Oid **param_types, int *num_params);
#endif /* PARAMS_H */ #endif /* PARAMS_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.341 2007/02/20 17:32:17 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.342 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1021,15 +1021,14 @@ typedef struct GrantRoleStmt ...@@ -1021,15 +1021,14 @@ typedef struct GrantRoleStmt
* *
* We support "COPY relation FROM file", "COPY relation TO file", and * We support "COPY relation FROM file", "COPY relation TO file", and
* "COPY (query) TO file". In any given CopyStmt, exactly one of "relation" * "COPY (query) TO file". In any given CopyStmt, exactly one of "relation"
* and "query" must be non-NULL. Note: "query" is a SelectStmt before * and "query" must be non-NULL.
* parse analysis, and a Query afterwards.
* ---------------------- * ----------------------
*/ */
typedef struct CopyStmt typedef struct CopyStmt
{ {
NodeTag type; NodeTag type;
RangeVar *relation; /* the relation to copy */ RangeVar *relation; /* the relation to copy */
Query *query; /* the query to copy */ Node *query; /* the SELECT query to copy */
List *attlist; /* List of column names (as Strings), or NIL List *attlist; /* List of column names (as Strings), or NIL
* for all columns */ * for all columns */
bool is_from; /* TO or FROM */ bool is_from; /* TO or FROM */
...@@ -1487,8 +1486,6 @@ typedef struct IndexStmt ...@@ -1487,8 +1486,6 @@ typedef struct IndexStmt
List *indexParams; /* a list of IndexElem */ List *indexParams; /* a list of IndexElem */
List *options; /* options from WITH clause */ List *options; /* options from WITH clause */
Node *whereClause; /* qualification (partial-index predicate) */ Node *whereClause; /* qualification (partial-index predicate) */
List *rangetable; /* range table for qual and/or expressions,
* filled in by transformStmt() */
bool unique; /* is index unique? */ bool unique; /* is index unique? */
bool primary; /* is index on primary key? */ bool primary; /* is index on primary key? */
bool isconstraint; /* is it from a CONSTRAINT clause? */ bool isconstraint; /* is it from a CONSTRAINT clause? */
...@@ -1713,7 +1710,7 @@ typedef struct ViewStmt ...@@ -1713,7 +1710,7 @@ typedef struct ViewStmt
NodeTag type; NodeTag type;
RangeVar *view; /* the view to be created */ RangeVar *view; /* the view to be created */
List *aliases; /* target column names */ List *aliases; /* target column names */
Query *query; /* the SQL statement */ Node *query; /* the SELECT query */
bool replace; /* replace an existing view? */ bool replace; /* replace an existing view? */
} ViewStmt; } ViewStmt;
...@@ -1805,7 +1802,7 @@ typedef struct VacuumStmt ...@@ -1805,7 +1802,7 @@ typedef struct VacuumStmt
typedef struct ExplainStmt typedef struct ExplainStmt
{ {
NodeTag type; NodeTag type;
Query *query; /* the query */ Node *query; /* the query (as a raw parse tree) */
bool verbose; /* print plan info */ bool verbose; /* print plan info */
bool analyze; /* get statistics by executing plan */ bool analyze; /* get statistics by executing plan */
} ExplainStmt; } ExplainStmt;
...@@ -1940,9 +1937,8 @@ typedef struct PrepareStmt ...@@ -1940,9 +1937,8 @@ typedef struct PrepareStmt
{ {
NodeTag type; NodeTag type;
char *name; /* Name of plan, arbitrary */ char *name; /* Name of plan, arbitrary */
List *argtypes; /* Types of parameters (TypeNames) */ List *argtypes; /* Types of parameters (List of TypeName) */
List *argtype_oids; /* Types of parameters (OIDs) */ Node *query; /* The query itself (as a raw parsetree) */
Query *query; /* The query itself */
} PrepareStmt; } PrepareStmt;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.35 2007/01/05 22:19:56 momjian Exp $ * $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.36 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,6 +21,10 @@ extern List *parse_analyze(Node *parseTree, const char *sourceText, ...@@ -21,6 +21,10 @@ extern List *parse_analyze(Node *parseTree, const char *sourceText,
extern List *parse_analyze_varparams(Node *parseTree, const char *sourceText, extern List *parse_analyze_varparams(Node *parseTree, const char *sourceText,
Oid **paramTypes, int *numParams); Oid **paramTypes, int *numParams);
extern List *parse_sub_analyze(Node *parseTree, ParseState *parentParseState); extern List *parse_sub_analyze(Node *parseTree, ParseState *parentParseState);
extern IndexStmt *analyzeIndexStmt(IndexStmt *stmt, const char *queryString);
extern void analyzeRuleStmt(RuleStmt *stmt, const char *queryString,
List **actions, Node **whereClause);
extern List *analyzeCreateSchemaStmt(CreateSchemaStmt *stmt); extern List *analyzeCreateSchemaStmt(CreateSchemaStmt *stmt);
extern void CheckSelectLocking(Query *qry); extern void CheckSelectLocking(Query *qry);
extern void applyLockingClause(Query *qry, Index rtindex, extern void applyLockingClause(Query *qry, Index rtindex,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.23 2007/01/05 22:19:57 momjian Exp $ * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.24 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,7 +16,15 @@ ...@@ -16,7 +16,15 @@
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
extern void DefineQueryRewrite(RuleStmt *args); extern void DefineRule(RuleStmt *stmt, const char *queryString);
extern void DefineQueryRewrite(char *rulename,
RangeVar *event_obj,
Node *event_qual,
CmdType event_type,
bool is_instead,
bool replace,
List *action);
extern void RenameRewriteRule(Oid owningRel, const char *oldName, extern void RenameRewriteRule(Oid owningRel, const char *oldName,
const char *newName); const char *newName);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/tcop/pquery.h,v 1.41 2007/02/20 17:32:17 tgl Exp $ * $PostgreSQL: pgsql/src/include/tcop/pquery.h,v 1.42 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -33,7 +33,7 @@ extern void PortalStart(Portal portal, ParamListInfo params, ...@@ -33,7 +33,7 @@ extern void PortalStart(Portal portal, ParamListInfo params,
extern void PortalSetResultFormat(Portal portal, int nFormats, extern void PortalSetResultFormat(Portal portal, int nFormats,
int16 *formats); int16 *formats);
extern bool PortalRun(Portal portal, long count, extern bool PortalRun(Portal portal, long count, bool isTopLevel,
DestReceiver *dest, DestReceiver *altdest, DestReceiver *dest, DestReceiver *altdest,
char *completionTag); char *completionTag);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.31 2007/02/20 17:32:17 tgl Exp $ * $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.32 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,8 +17,9 @@ ...@@ -17,8 +17,9 @@
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
extern void ProcessUtility(Node *parsetree, ParamListInfo params, extern void ProcessUtility(Node *parsetree, const char *queryString,
DestReceiver *dest, char *completionTag); ParamListInfo params, bool isTopLevel,
DestReceiver *dest, char *completionTag);
extern bool UtilityReturnsTuples(Node *parsetree); extern bool UtilityReturnsTuples(Node *parsetree);
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/memutils.h,v 1.61 2007/01/05 22:19:59 momjian Exp $ * $PostgreSQL: pgsql/src/include/utils/memutils.h,v 1.62 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -75,8 +75,7 @@ extern DLLIMPORT MemoryContext MessageContext; ...@@ -75,8 +75,7 @@ extern DLLIMPORT MemoryContext MessageContext;
extern DLLIMPORT MemoryContext TopTransactionContext; extern DLLIMPORT MemoryContext TopTransactionContext;
extern DLLIMPORT MemoryContext CurTransactionContext; extern DLLIMPORT MemoryContext CurTransactionContext;
/* These two are transient links to contexts owned by other objects: */ /* This is a transient link to the active portal's memory context: */
extern DLLIMPORT MemoryContext QueryContext;
extern DLLIMPORT MemoryContext PortalContext; extern DLLIMPORT MemoryContext PortalContext;
......
This diff is collapsed.
This diff is collapsed.
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/resowner.h,v 1.10 2007/01/05 22:19:59 momjian Exp $ * $PostgreSQL: pgsql/src/include/utils/resowner.h,v 1.11 2007/03/13 00:33:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "storage/buf.h" #include "storage/buf.h"
#include "utils/catcache.h" #include "utils/catcache.h"
#include "utils/plancache.h"
/* /*
...@@ -106,6 +107,13 @@ extern void ResourceOwnerRememberRelationRef(ResourceOwner owner, ...@@ -106,6 +107,13 @@ extern void ResourceOwnerRememberRelationRef(ResourceOwner owner,
extern void ResourceOwnerForgetRelationRef(ResourceOwner owner, extern void ResourceOwnerForgetRelationRef(ResourceOwner owner,
Relation rel); Relation rel);
/* support for plancache refcount management */
extern void ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner);
extern void ResourceOwnerRememberPlanCacheRef(ResourceOwner owner,
CachedPlan *plan);
extern void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner,
CachedPlan *plan);
/* support for tupledesc refcount management */ /* support for tupledesc refcount management */
extern void ResourceOwnerEnlargeTupleDescs(ResourceOwner owner); extern void ResourceOwnerEnlargeTupleDescs(ResourceOwner owner);
extern void ResourceOwnerRememberTupleDesc(ResourceOwner owner, extern void ResourceOwnerRememberTupleDesc(ResourceOwner owner,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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