|
65 | 65 | #include"utils/syscache.h" |
66 | 66 |
|
67 | 67 |
|
| 68 | +/* |
| 69 | + * We must skip "overhead" operations that involve database access when the |
| 70 | + * cached plan's subject statement is a transaction control command. |
| 71 | + */ |
| 72 | +#defineIsTransactionStmtPlan(plansource) \ |
| 73 | +((plansource)->raw_parse_tree && \ |
| 74 | + IsA((plansource)->raw_parse_tree, TransactionStmt)) |
| 75 | + |
68 | 76 | /* |
69 | 77 | * This is the head of the backend's list of "saved" CachedPlanSources (i.e., |
70 | 78 | * those that are in long-lived storage and are examined for sinval events). |
@@ -352,9 +360,10 @@ CompleteCachedPlan(CachedPlanSource *plansource, |
352 | 360 | /* |
353 | 361 | * Use the planner machinery to extract dependencies. Data is saved in |
354 | 362 | * query_context. (We assume that not a lot of extra cruft is created by |
355 | | - * this call.) We can skip this for one-shot plans. |
| 363 | + * this call.) We can skip this for one-shot plans, and transaction |
| 364 | + * control commands have no such dependencies anyway. |
356 | 365 | */ |
357 | | -if (!plansource->is_oneshot) |
| 366 | +if (!plansource->is_oneshot&& !IsTransactionStmtPlan(plansource)) |
358 | 367 | extract_query_dependencies((Node*)querytree_list, |
359 | 368 | &plansource->relationOids, |
360 | 369 | &plansource->invalItems); |
@@ -384,9 +393,12 @@ CompleteCachedPlan(CachedPlanSource *plansource, |
384 | 393 |
|
385 | 394 | /* |
386 | 395 | * Fetch current search_path into dedicated context, but do any |
387 | | - * recalculation work required in caller's context. |
| 396 | + * recalculation work required in caller's context. We *must* skip this |
| 397 | + * for transaction control commands, because this could result in catalog |
| 398 | + * accesses. |
388 | 399 | */ |
389 | | -plansource->search_path=GetOverrideSearchPath(source_context); |
| 400 | +if (!IsTransactionStmtPlan(plansource)) |
| 401 | +plansource->search_path=GetOverrideSearchPath(source_context); |
390 | 402 |
|
391 | 403 | plansource->is_complete= true; |
392 | 404 | plansource->is_valid= true; |
@@ -537,9 +549,11 @@ RevalidateCachedQuery(CachedPlanSource *plansource) |
537 | 549 | /* |
538 | 550 | * For one-shot plans, we do not support revalidation checking; it's |
539 | 551 | * assumed the query is parsed, planned, and executed in one transaction, |
540 | | - * so that no lock re-acquisition is necessary. |
| 552 | + * so that no lock re-acquisition is necessary. Also, there is never |
| 553 | + * any need to revalidate plans for transaction control commands (and |
| 554 | + * we mustn't risk any catalog accesses when handling those). |
541 | 555 | */ |
542 | | -if (plansource->is_oneshot) |
| 556 | +if (plansource->is_oneshot||IsTransactionStmtPlan(plansource)) |
543 | 557 | { |
544 | 558 | Assert(plansource->is_valid); |
545 | 559 | returnNIL; |
@@ -859,7 +873,8 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, |
859 | 873 | * compared to parse analysis + planning, I'm not going to contort the |
860 | 874 | * code enough to avoid that. |
861 | 875 | */ |
862 | | -PushOverrideSearchPath(plansource->search_path); |
| 876 | +if (plansource->search_path) |
| 877 | +PushOverrideSearchPath(plansource->search_path); |
863 | 878 |
|
864 | 879 | /* |
865 | 880 | * If a snapshot is already set (the normal case), we can just use that |
@@ -894,7 +909,8 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist, |
894 | 909 | PopActiveSnapshot(); |
895 | 910 |
|
896 | 911 | /* Now we can restore current search path */ |
897 | | -PopOverrideSearchPath(); |
| 912 | +if (plansource->search_path) |
| 913 | +PopOverrideSearchPath(); |
898 | 914 |
|
899 | 915 | /* |
900 | 916 | * Normally we make a dedicated memory context for the CachedPlan and its |
@@ -965,6 +981,9 @@ choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams) |
965 | 981 | /* Otherwise, never any point in a custom plan if there's no parameters */ |
966 | 982 | if (boundParams==NULL) |
967 | 983 | return false; |
| 984 | +/* ... nor for transaction control statements */ |
| 985 | +if (IsTransactionStmtPlan(plansource)) |
| 986 | +return false; |
968 | 987 |
|
969 | 988 | /* See if caller wants to force the decision */ |
970 | 989 | if (plansource->cursor_options&CURSOR_OPT_GENERIC_PLAN) |
@@ -1267,7 +1286,8 @@ CopyCachedPlan(CachedPlanSource *plansource) |
1267 | 1286 | newsource->resultDesc=CreateTupleDescCopy(plansource->resultDesc); |
1268 | 1287 | else |
1269 | 1288 | newsource->resultDesc=NULL; |
1270 | | -newsource->search_path=CopyOverrideSearchPath(plansource->search_path); |
| 1289 | +if (plansource->search_path) |
| 1290 | +newsource->search_path=CopyOverrideSearchPath(plansource->search_path); |
1271 | 1291 | newsource->context=source_context; |
1272 | 1292 |
|
1273 | 1293 | querytree_context=AllocSetContextCreate(source_context, |
@@ -1619,6 +1639,10 @@ PlanCacheRelCallback(Datum arg, Oid relid) |
1619 | 1639 | if (!plansource->is_valid) |
1620 | 1640 | continue; |
1621 | 1641 |
|
| 1642 | +/* Never invalidate transaction control commands */ |
| 1643 | +if (IsTransactionStmtPlan(plansource)) |
| 1644 | +continue; |
| 1645 | + |
1622 | 1646 | /* |
1623 | 1647 | * Check the dependency list for the rewritten querytree. |
1624 | 1648 | */ |
@@ -1683,6 +1707,10 @@ PlanCacheFuncCallback(Datum arg, int cacheid, uint32 hashvalue) |
1683 | 1707 | if (!plansource->is_valid) |
1684 | 1708 | continue; |
1685 | 1709 |
|
| 1710 | +/* Never invalidate transaction control commands */ |
| 1711 | +if (IsTransactionStmtPlan(plansource)) |
| 1712 | +continue; |
| 1713 | + |
1686 | 1714 | /* |
1687 | 1715 | * Check the dependency list for the rewritten querytree. |
1688 | 1716 | */ |
@@ -1772,6 +1800,11 @@ ResetPlanCache(void) |
1772 | 1800 | * We *must not* mark transaction control statements as invalid, |
1773 | 1801 | * particularly not ROLLBACK, because they may need to be executed in |
1774 | 1802 | * aborted transactions when we can't revalidate them (cf bug #5269). |
| 1803 | + */ |
| 1804 | +if (IsTransactionStmtPlan(plansource)) |
| 1805 | +continue; |
| 1806 | + |
| 1807 | +/* |
1775 | 1808 | * In general there is no point in invalidating utility statements |
1776 | 1809 | * since they have no plans anyway. So invalidate it only if it |
1777 | 1810 | * contains at least one non-utility statement, or contains a utility |
|