TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * delay_execution.c
4 : * Test module to allow delay between parsing and execution of a query.
5 : *
6 : * The delay is implemented by taking and immediately releasing a specified
7 : * advisory lock. If another process has previously taken that lock, the
8 : * current process will be blocked until the lock is released; otherwise,
9 : * there's no effect. This allows an isolationtester script to reliably
10 : * test behaviors where some specified action happens in another backend
11 : * between parsing and execution of any desired query.
12 : *
13 : * Copyright (c) 2020-2023, PostgreSQL Global Development Group
14 : *
15 : * IDENTIFICATION
16 : * src/test/modules/delay_execution/delay_execution.c
17 : *
18 : *-------------------------------------------------------------------------
19 : */
20 :
21 : #include "postgres.h"
22 :
23 : #include <limits.h>
24 :
25 : #include "optimizer/planner.h"
26 : #include "utils/builtins.h"
27 : #include "utils/guc.h"
28 : #include "utils/inval.h"
29 :
30 :
31 CBC 2 : PG_MODULE_MAGIC;
32 :
33 : /* GUC: advisory lock ID to use. Zero disables the feature. */
34 : static int post_planning_lock_id = 0;
35 :
36 : /* Save previous planner hook user to be a good citizen */
37 : static planner_hook_type prev_planner_hook = NULL;
38 :
39 ECB :
40 : /* planner_hook function to provide the desired delay */
41 : static PlannedStmt *
42 GIC 15 : delay_execution_planner(Query *parse, const char *query_string,
43 : int cursorOptions, ParamListInfo boundParams)
44 : {
45 ECB : PlannedStmt *result;
46 EUB :
47 : /* Invoke the planner, possibly via a previous hook user */
48 GIC 15 : if (prev_planner_hook)
49 LBC 0 : result = prev_planner_hook(parse, query_string, cursorOptions,
50 : boundParams);
51 : else
52 GIC 15 : result = standard_planner(parse, query_string, cursorOptions,
53 ECB : boundParams);
54 :
55 : /* If enabled, delay by taking and releasing the specified lock */
56 GIC 15 : if (post_planning_lock_id != 0)
57 ECB : {
58 GIC 15 : DirectFunctionCall1(pg_advisory_lock_int8,
59 : Int64GetDatum((int64) post_planning_lock_id));
60 15 : DirectFunctionCall1(pg_advisory_unlock_int8,
61 : Int64GetDatum((int64) post_planning_lock_id));
62 :
63 : /*
64 ECB : * Ensure that we notice any pending invalidations, since the advisory
65 : * lock functions don't do this.
66 : */
67 CBC 15 : AcceptInvalidationMessages();
68 : }
69 :
70 GIC 15 : return result;
71 : }
72 ECB :
73 : /* Module load function */
74 : void
75 CBC 2 : _PG_init(void)
76 : {
77 : /* Set up the GUC to control which lock is used */
78 GIC 2 : DefineCustomIntVariable("delay_execution.post_planning_lock_id",
79 : "Sets the advisory lock ID to be locked/unlocked after planning.",
80 : "Zero disables the delay.",
81 : &post_planning_lock_id,
82 : 0,
83 : 0, INT_MAX,
84 : PGC_USERSET,
85 : 0,
86 : NULL,
87 ECB : NULL,
88 : NULL);
89 :
90 CBC 2 : MarkGUCPrefixReserved("delay_execution");
91 ECB :
92 : /* Install our hook */
93 GIC 2 : prev_planner_hook = planner_hook;
94 2 : planner_hook = delay_execution_planner;
95 2 : }
|