Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc98a923

Browse files
committed
Fix failure to ensure that a snapshot is available to datatype input functions
when they are invoked by the parser. We had been setting up a snapshot atplan time but really it needs to be done earlier, before parse analysis.Per report from Dmitry Koterov.Also fix two related problems discovered while poking at this one:exec_bind_message called datatype input functions without establishing asnapshot, and SET CONSTRAINTS IMMEDIATE could call trigger functions withoutestablishing a snapshot.Backpatch to 8.2. The underlying problem goes much further back, but it ismasked in 8.1 and before because we didn't attempt to invoke domain checkconstraints within datatype input. It would only be exposed if a C-languagedatatype input function used the snapshot; which evidently none do, or we'dhave heard complaints sooner. Since this code has changed a lot over time,a back-patch is hardly risk-free, and so I'm disinclined to patch furtherthan absolutely necessary.
1 parent0f864a6 commitc98a923

File tree

5 files changed

+145
-14
lines changed

5 files changed

+145
-14
lines changed

‎src/backend/commands/trigger.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.241 2008/11/21 20:14:27 mha Exp $
10+
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.242 2008/12/13 02:00:18 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -3716,11 +3716,27 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
37163716
if (!stmt->deferred)
37173717
{
37183718
AfterTriggerEventList*events=&afterTriggers->events;
3719+
boolsnapshot_set= false;
37193720

37203721
while (afterTriggerMarkEvents(events,NULL, true))
37213722
{
37223723
CommandIdfiring_id=afterTriggers->firing_counter++;
37233724

3725+
/*
3726+
* Make sure a snapshot has been established in case trigger
3727+
* functions need one. Note that we avoid setting a snapshot if
3728+
* we don't find at least one trigger that has to be fired now.
3729+
* This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
3730+
* ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
3731+
* at the start of a transaction it's not possible for any trigger
3732+
* events to be queued yet.)
3733+
*/
3734+
if (!snapshot_set)
3735+
{
3736+
PushActiveSnapshot(GetTransactionSnapshot());
3737+
snapshot_set= true;
3738+
}
3739+
37243740
/*
37253741
* We can delete fired events if we are at top transaction level,
37263742
* but we'd better not if inside a subtransaction, since the
@@ -3730,6 +3746,9 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
37303746
!IsSubTransaction()))
37313747
break;/* all fired */
37323748
}
3749+
3750+
if (snapshot_set)
3751+
PopActiveSnapshot();
37333752
}
37343753
}
37353754

‎src/backend/parser/analyze.c

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
1818
* Portions Copyright (c) 1994, Regents of the University of California
1919
*
20-
*$PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.383 2008/11/15 19:43:46 tgl Exp $
20+
*$PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.384 2008/12/13 02:00:19 tgl Exp $
2121
*
2222
*-------------------------------------------------------------------------
2323
*/
@@ -217,6 +217,55 @@ transformStmt(ParseState *pstate, Node *parseTree)
217217
returnresult;
218218
}
219219

220+
/*
221+
* analyze_requires_snapshot
222+
*Returns true if a snapshot must be set before doing parse analysis
223+
*on the given raw parse tree.
224+
*
225+
* Classification here should match transformStmt().
226+
*/
227+
bool
228+
analyze_requires_snapshot(Node*parseTree)
229+
{
230+
boolresult;
231+
232+
switch (nodeTag(parseTree))
233+
{
234+
/*
235+
* Optimizable statements
236+
*/
237+
caseT_InsertStmt:
238+
caseT_DeleteStmt:
239+
caseT_UpdateStmt:
240+
caseT_SelectStmt:
241+
result= true;
242+
break;
243+
244+
/*
245+
* Special cases
246+
*/
247+
caseT_DeclareCursorStmt:
248+
/* yes, because it's analyzed just like SELECT */
249+
result= true;
250+
break;
251+
252+
caseT_ExplainStmt:
253+
/*
254+
* We only need a snapshot in varparams case, but it doesn't seem
255+
* worth complicating this function's API to distinguish that.
256+
*/
257+
result= true;
258+
break;
259+
260+
default:
261+
/* utility statements don't have any active parse analysis */
262+
result= false;
263+
break;
264+
}
265+
266+
returnresult;
267+
}
268+
220269
/*
221270
* transformDeleteStmt -
222271
* transforms a Delete Statement

‎src/backend/tcop/postgres.c

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.560 2008/12/09 15:59:39 heikki Exp $
11+
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.561 2008/12/13 02:00:19 tgl Exp $
1212
*
1313
* NOTES
1414
* this is the "main" module of the postgres backend and
@@ -685,6 +685,9 @@ pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)
685685
if (querytree->commandType==CMD_UTILITY)
686686
returnNULL;
687687

688+
/* Planner must have a snapshot in case it calls user-defined functions. */
689+
Assert(ActiveSnapshotSet());
690+
688691
TRACE_POSTGRESQL_QUERY_PLAN_START();
689692

690693
if (log_planner_stats)
@@ -872,6 +875,7 @@ exec_simple_query(const char *query_string)
872875
foreach(parsetree_item,parsetree_list)
873876
{
874877
Node*parsetree= (Node*)lfirst(parsetree_item);
878+
boolsnapshot_set= false;
875879
constchar*commandTag;
876880
charcompletionTag[COMPLETION_TAG_BUFSIZE];
877881
List*querytree_list,
@@ -913,6 +917,15 @@ exec_simple_query(const char *query_string)
913917
/* If we got a cancel signal in parsing or prior command, quit */
914918
CHECK_FOR_INTERRUPTS();
915919

920+
/*
921+
* Set up a snapshot if parse analysis/planning will need one.
922+
*/
923+
if (analyze_requires_snapshot(parsetree))
924+
{
925+
PushActiveSnapshot(GetTransactionSnapshot());
926+
snapshot_set= true;
927+
}
928+
916929
/*
917930
* OK to analyze, rewrite, and plan this query.
918931
*
@@ -924,7 +937,11 @@ exec_simple_query(const char *query_string)
924937
querytree_list=pg_analyze_and_rewrite(parsetree,query_string,
925938
NULL,0);
926939

927-
plantree_list=pg_plan_queries(querytree_list,0,NULL, true);
940+
plantree_list=pg_plan_queries(querytree_list,0,NULL, false);
941+
942+
/* Done with the snapshot used for parsing/planning */
943+
if (snapshot_set)
944+
PopActiveSnapshot();
928945

929946
/* If we got a cancel signal in analysis or planning, quit */
930947
CHECK_FOR_INTERRUPTS();
@@ -939,7 +956,7 @@ exec_simple_query(const char *query_string)
939956

940957
/*
941958
* We don't have to copy anything into the portal, because everything
942-
* we arepasssing here is in MessageContext, which will outlive the
959+
* we arepassing here is in MessageContext, which will outlive the
943960
* portal anyway.
944961
*/
945962
PortalDefineQuery(portal,
@@ -1178,6 +1195,7 @@ exec_parse_message(const char *query_string,/* string to execute */
11781195
if (parsetree_list!=NIL)
11791196
{
11801197
Query*query;
1198+
boolsnapshot_set= false;
11811199
inti;
11821200

11831201
raw_parse_tree= (Node*)linitial(parsetree_list);
@@ -1202,6 +1220,15 @@ exec_parse_message(const char *query_string,/* string to execute */
12021220
errmsg("current transaction is aborted, "
12031221
"commands ignored until end of transaction block")));
12041222

1223+
/*
1224+
* Set up a snapshot if parse analysis/planning will need one.
1225+
*/
1226+
if (analyze_requires_snapshot(raw_parse_tree))
1227+
{
1228+
PushActiveSnapshot(GetTransactionSnapshot());
1229+
snapshot_set= true;
1230+
}
1231+
12051232
/*
12061233
* OK to analyze, rewrite, and plan this query. Note that the
12071234
* originally specified parameter set is not required to be complete,
@@ -1249,9 +1276,13 @@ exec_parse_message(const char *query_string,/* string to execute */
12491276
}
12501277
else
12511278
{
1252-
stmt_list=pg_plan_queries(querytree_list,0,NULL,true);
1279+
stmt_list=pg_plan_queries(querytree_list,0,NULL,false);
12531280
fully_planned= true;
12541281
}
1282+
1283+
/* Done with the snapshot used for parsing/planning */
1284+
if (snapshot_set)
1285+
PopActiveSnapshot();
12551286
}
12561287
else
12571288
{
@@ -1375,6 +1406,7 @@ exec_bind_message(StringInfo input_message)
13751406
List*plan_list;
13761407
MemoryContextoldContext;
13771408
boolsave_log_statement_stats=log_statement_stats;
1409+
boolsnapshot_set= false;
13781410
charmsec_str[32];
13791411

13801412
/* Get the fixed part of the message */
@@ -1494,6 +1526,17 @@ exec_bind_message(StringInfo input_message)
14941526
else
14951527
saved_stmt_name=NULL;
14961528

1529+
/*
1530+
* Set a snapshot if we have parameters to fetch (since the input
1531+
* functions might need it) or the query isn't a utility command (and
1532+
* hence could require redoing parse analysis and planning).
1533+
*/
1534+
if (numParams>0||analyze_requires_snapshot(psrc->raw_parse_tree))
1535+
{
1536+
PushActiveSnapshot(GetTransactionSnapshot());
1537+
snapshot_set= true;
1538+
}
1539+
14971540
/*
14981541
* Fetch parameters, if any, and store in the portal's memory context.
14991542
*/
@@ -1682,7 +1725,7 @@ exec_bind_message(StringInfo input_message)
16821725
*/
16831726
oldContext=MemoryContextSwitchTo(PortalGetHeapMemory(portal));
16841727
query_list=copyObject(cplan->stmt_list);
1685-
plan_list=pg_plan_queries(query_list,0,params,true);
1728+
plan_list=pg_plan_queries(query_list,0,params,false);
16861729
MemoryContextSwitchTo(oldContext);
16871730

16881731
/* We no longer need the cached plan refcount ... */
@@ -1691,6 +1734,10 @@ exec_bind_message(StringInfo input_message)
16911734
cplan=NULL;
16921735
}
16931736

1737+
/* Done with the snapshot used for parameter I/O and parsing/planning */
1738+
if (snapshot_set)
1739+
PopActiveSnapshot();
1740+
16941741
/*
16951742
* Define portal and start execution.
16961743
*/

‎src/backend/utils/cache/plancache.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
* Portions Copyright (c) 1994, Regents of the University of California
3636
*
3737
* IDENTIFICATION
38-
* $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.23 2008/10/04 21:56:54 tgl Exp $
38+
* $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.24 2008/12/13 02:00:20 tgl Exp $
3939
*
4040
*-------------------------------------------------------------------------
4141
*/
@@ -463,6 +463,7 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
463463
*/
464464
if (!plan)
465465
{
466+
boolsnapshot_set= false;
466467
List*slist;
467468
TupleDescresultDesc;
468469

@@ -472,6 +473,19 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
472473
*/
473474
PushOverrideSearchPath(plansource->search_path);
474475

476+
/*
477+
* If a snapshot is already set (the normal case), we can just use
478+
* that for parsing/planning. But if it isn't, install one. Note:
479+
* no point in checking whether parse analysis requires a snapshot;
480+
* utility commands don't have invalidatable plans, so we'd not get
481+
* here for such a command.
482+
*/
483+
if (!ActiveSnapshotSet())
484+
{
485+
PushActiveSnapshot(GetTransactionSnapshot());
486+
snapshot_set= true;
487+
}
488+
475489
/*
476490
* Run parse analysis and rule rewriting. The parser tends to
477491
* scribble on its input, so we must copy the raw parse tree to
@@ -488,13 +502,9 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
488502
{
489503
/*
490504
* Generate plans for queries.
491-
*
492-
* If a snapshot is already set (the normal case), we can just use
493-
* that for planning. But if it isn't, we have to tell
494-
* pg_plan_queries to make a snap if it needs one.
495505
*/
496506
slist=pg_plan_queries(slist,plansource->cursor_options,
497-
NULL,!ActiveSnapshotSet());
507+
NULL,false);
498508
}
499509

500510
/*
@@ -525,6 +535,10 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
525535
MemoryContextSwitchTo(oldcxt);
526536
}
527537

538+
/* Release snapshot if we got one */
539+
if (snapshot_set)
540+
PopActiveSnapshot();
541+
528542
/* Now we can restore current search path */
529543
PopOverrideSearchPath();
530544

‎src/include/parser/analyze.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.38 2008/01/01 19:45:58 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.39 2008/12/13 02:00:20 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -25,6 +25,8 @@ extern Query *parse_analyze_varparams(Node *parseTree, const char *sourceText,
2525
externQuery*parse_sub_analyze(Node*parseTree,ParseState*parentParseState);
2626
externQuery*transformStmt(ParseState*pstate,Node*parseTree);
2727

28+
externboolanalyze_requires_snapshot(Node*parseTree);
29+
2830
externvoidCheckSelectLocking(Query*qry);
2931
externvoidapplyLockingClause(Query*qry,Indexrtindex,
3032
boolforUpdate,boolnoWait);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp