Skip to content

Commit b9527e9

Browse files
committed
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.
1 parent f84308f commit b9527e9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2478
-1354
lines changed

src/backend/access/transam/xact.c

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.235 2007/03/12 22:09:27 petere Exp $
13+
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.236 2007/03/13 00:33:38 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -2504,12 +2504,13 @@ AbortCurrentTransaction(void)
25042504
* could issue more commands and possibly cause a failure after the statement
25052505
* completes). Subtransactions are verboten too.
25062506
*
2507-
* stmtNode: pointer to parameter block for statement; this is used in
2508-
* a very klugy way to determine whether we are inside a function.
2509-
* stmtType: statement type name for error messages.
2507+
* isTopLevel: passed down from ProcessUtility to determine whether we are
2508+
* inside a function. (We will always fail if this is false, but it's
2509+
* convenient to centralize the check here instead of making callers do it.)
2510+
* stmtType: statement type name, for error messages.
25102511
*/
25112512
void
2512-
PreventTransactionChain(void *stmtNode, const char *stmtType)
2513+
PreventTransactionChain(bool isTopLevel, const char *stmtType)
25132514
{
25142515
/*
25152516
* xact block already started?
@@ -2532,11 +2533,9 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
25322533
stmtType)));
25332534

25342535
/*
2535-
* Are we inside a function call? If the statement's parameter block was
2536-
* allocated in QueryContext, assume it is an interactive command.
2537-
* Otherwise assume it is coming from a function.
2536+
* inside a function call?
25382537
*/
2539-
if (!MemoryContextContains(QueryContext, stmtNode))
2538+
if (!isTopLevel)
25402539
ereport(ERROR,
25412540
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
25422541
/* translator: %s represents an SQL statement name */
@@ -2562,12 +2561,12 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
25622561
* use of the current statement's results. Likewise subtransactions.
25632562
* Thus this is an inverse for PreventTransactionChain.
25642563
*
2565-
* stmtNode: pointer to parameter block for statement; this is used in
2566-
* a very klugy way to determine whether we are inside a function.
2567-
* stmtType: statement type name for error messages.
2564+
* isTopLevel: passed down from ProcessUtility to determine whether we are
2565+
* inside a function.
2566+
* stmtType: statement type name, for error messages.
25682567
*/
25692568
void
2570-
RequireTransactionChain(void *stmtNode, const char *stmtType)
2569+
RequireTransactionChain(bool isTopLevel, const char *stmtType)
25712570
{
25722571
/*
25732572
* xact block already started?
@@ -2582,12 +2581,11 @@ RequireTransactionChain(void *stmtNode, const char *stmtType)
25822581
return;
25832582

25842583
/*
2585-
* Are we inside a function call? If the statement's parameter block was
2586-
* allocated in QueryContext, assume it is an interactive command.
2587-
* Otherwise assume it is coming from a function.
2584+
* inside a function call?
25882585
*/
2589-
if (!MemoryContextContains(QueryContext, stmtNode))
2586+
if (!isTopLevel)
25902587
return;
2588+
25912589
ereport(ERROR,
25922590
(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
25932591
/* translator: %s represents an SQL statement name */
@@ -2602,11 +2600,11 @@ RequireTransactionChain(void *stmtNode, const char *stmtType)
26022600
* a transaction block than when running as single commands. ANALYZE is
26032601
* currently the only example.
26042602
*
2605-
* stmtNode: pointer to parameter block for statement; this is used in
2606-
* a very klugy way to determine whether we are inside a function.
2603+
* isTopLevel: passed down from ProcessUtility to determine whether we are
2604+
* inside a function.
26072605
*/
26082606
bool
2609-
IsInTransactionChain(void *stmtNode)
2607+
IsInTransactionChain(bool isTopLevel)
26102608
{
26112609
/*
26122610
* Return true on same conditions that would make PreventTransactionChain
@@ -2618,7 +2616,7 @@ IsInTransactionChain(void *stmtNode)
26182616
if (IsSubTransaction())
26192617
return true;
26202618

2621-
if (!MemoryContextContains(QueryContext, stmtNode))
2619+
if (!isTopLevel)
26222620
return true;
26232621

26242622
if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&

src/backend/bootstrap/bootparse.y

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.87 2007/03/07 13:35:02 alvherre Exp $
12+
* $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.88 2007/03/13 00:33:39 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -252,7 +252,7 @@ Boot_DeclareIndexStmt:
252252
LexIDStr($8),
253253
NULL,
254254
$10,
255-
NULL, NIL, NIL,
255+
NULL, NIL,
256256
false, false, false,
257257
false, false, true, false, false);
258258
do_end();
@@ -270,7 +270,7 @@ Boot_DeclareUniqueIndexStmt:
270270
LexIDStr($9),
271271
NULL,
272272
$11,
273-
NULL, NIL, NIL,
273+
NULL, NIL,
274274
true, false, false,
275275
false, false, true, false, false);
276276
do_end();

src/backend/commands/cluster.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.156 2007/02/01 19:10:25 momjian Exp $
14+
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.157 2007/03/13 00:33:39 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -82,7 +82,7 @@ static List *get_tables_to_cluster(MemoryContext cluster_context);
8282
*---------------------------------------------------------------------------
8383
*/
8484
void
85-
cluster(ClusterStmt *stmt)
85+
cluster(ClusterStmt *stmt, bool isTopLevel)
8686
{
8787
if (stmt->relation != NULL)
8888
{
@@ -173,7 +173,7 @@ cluster(ClusterStmt *stmt)
173173
* We cannot run this form of CLUSTER inside a user transaction block;
174174
* we'd be holding locks way too long.
175175
*/
176-
PreventTransactionChain((void *) stmt, "CLUSTER");
176+
PreventTransactionChain(isTopLevel, "CLUSTER");
177177

178178
/*
179179
* Create special memory context for cross-transaction storage.

src/backend/commands/copy.c

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.277 2007/03/03 19:32:54 neilc Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.278 2007/03/13 00:33:39 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -713,7 +713,7 @@ CopyLoadRawBuf(CopyState cstate)
713713
* the table.
714714
*/
715715
uint64
716-
DoCopy(const CopyStmt *stmt)
716+
DoCopy(const CopyStmt *stmt, const char *queryString)
717717
{
718718
CopyState cstate;
719719
bool is_from = stmt->is_from;
@@ -982,13 +982,11 @@ DoCopy(const CopyStmt *stmt)
982982
}
983983
else
984984
{
985-
Query *query = stmt->query;
986985
List *rewritten;
986+
Query *query;
987987
PlannedStmt *plan;
988988
DestReceiver *dest;
989989

990-
Assert(query);
991-
Assert(query->commandType == CMD_SELECT);
992990
Assert(!is_from);
993991
cstate->rel = NULL;
994992

@@ -998,33 +996,18 @@ DoCopy(const CopyStmt *stmt)
998996
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
999997
errmsg("COPY (SELECT) WITH OIDS is not supported")));
1000998

1001-
/* Query mustn't use INTO, either */
1002-
if (query->into)
1003-
ereport(ERROR,
1004-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1005-
errmsg("COPY (SELECT INTO) is not supported")));
1006-
1007999
/*
1008-
* The query has already been through parse analysis, but not
1009-
* rewriting or planning. Do that now.
1000+
* Run parse analysis and rewrite. Note this also acquires sufficient
1001+
* locks on the source table(s).
10101002
*
1011-
* Because the planner is not cool about not scribbling on its input,
1012-
* we make a preliminary copy of the source querytree. This prevents
1003+
* Because the parser and planner tend to scribble on their input, we
1004+
* make a preliminary copy of the source querytree. This prevents
10131005
* problems in the case that the COPY is in a portal or plpgsql
10141006
* function and is executed repeatedly. (See also the same hack in
1015-
* EXPLAIN, DECLARE CURSOR and PREPARE.) XXX the planner really
1016-
* shouldn't modify its input ... FIXME someday.
1007+
* DECLARE CURSOR and PREPARE.) XXX FIXME someday.
10171008
*/
1018-
query = copyObject(query);
1019-
1020-
/*
1021-
* Must acquire locks in case we didn't come fresh from the parser.
1022-
* XXX this also scribbles on query, another reason for copyObject
1023-
*/
1024-
AcquireRewriteLocks(query);
1025-
1026-
/* Rewrite through rule system */
1027-
rewritten = QueryRewrite(query);
1009+
rewritten = pg_analyze_and_rewrite((Node *) copyObject(stmt->query),
1010+
queryString, NULL, 0);
10281011

10291012
/* We don't expect more or less than one result query */
10301013
if (list_length(rewritten) != 1)
@@ -1033,6 +1016,12 @@ DoCopy(const CopyStmt *stmt)
10331016
query = (Query *) linitial(rewritten);
10341017
Assert(query->commandType == CMD_SELECT);
10351018

1019+
/* Query mustn't use INTO, either */
1020+
if (query->into)
1021+
ereport(ERROR,
1022+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1023+
errmsg("COPY (SELECT INTO) is not supported")));
1024+
10361025
/* plan the query */
10371026
plan = planner(query, false, 0, NULL);
10381027

src/backend/commands/dbcommands.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.192 2007/02/09 16:12:18 tgl Exp $
16+
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.193 2007/03/13 00:33:39 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -97,9 +97,6 @@ createdb(const CreatedbStmt *stmt)
9797
int encoding = -1;
9898
int dbconnlimit = -1;
9999

100-
/* don't call this in a transaction block */
101-
PreventTransactionChain((void *) stmt, "CREATE DATABASE");
102-
103100
/* Extract options from the statement node tree */
104101
foreach(option, stmt->options)
105102
{
@@ -545,8 +542,6 @@ dropdb(const char *dbname, bool missing_ok)
545542
Relation pgdbrel;
546543
HeapTuple tup;
547544

548-
PreventTransactionChain((void *) dbname, "DROP DATABASE");
549-
550545
AssertArg(dbname);
551546

552547
if (strcmp(dbname, get_database_name(MyDatabaseId)) == 0)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy