Age Owner Branch data 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-2025, 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/fmgrprotos.h"
27 : : #include "utils/guc.h"
28 : : #include "utils/inval.h"
29 : :
30 : :
1908 tgl@sss.pgh.pa.us 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 : :
40 : : /* planner_hook function to provide the desired delay */
41 : : static PlannedStmt *
42 : 15 : delay_execution_planner(Query *parse, const char *query_string,
43 : : int cursorOptions, ParamListInfo boundParams,
44 : : ExplainState *es)
45 : : {
46 : : PlannedStmt *result;
47 : :
48 : : /* Invoke the planner, possibly via a previous hook user */
49 [ - + ]: 15 : if (prev_planner_hook)
1908 tgl@sss.pgh.pa.us 50 :UBC 0 : result = prev_planner_hook(parse, query_string, cursorOptions,
51 : : boundParams, es);
52 : : else
1908 tgl@sss.pgh.pa.us 53 :CBC 15 : result = standard_planner(parse, query_string, cursorOptions,
54 : : boundParams, es);
55 : :
56 : : /* If enabled, delay by taking and releasing the specified lock */
57 [ + - ]: 15 : if (post_planning_lock_id != 0)
58 : : {
59 : 15 : DirectFunctionCall1(pg_advisory_lock_int8,
60 : : Int64GetDatum((int64) post_planning_lock_id));
61 : 15 : DirectFunctionCall1(pg_advisory_unlock_int8,
62 : : Int64GetDatum((int64) post_planning_lock_id));
63 : :
64 : : /*
65 : : * Ensure that we notice any pending invalidations, since the advisory
66 : : * lock functions don't do this.
67 : : */
68 : 15 : AcceptInvalidationMessages();
69 : : }
70 : :
71 : 15 : return result;
72 : : }
73 : :
74 : : /* Module load function */
75 : : void
76 : 2 : _PG_init(void)
77 : : {
78 : : /* Set up the GUC to control which lock is used */
79 : 2 : DefineCustomIntVariable("delay_execution.post_planning_lock_id",
80 : : "Sets the advisory lock ID to be locked/unlocked after planning.",
81 : : "Zero disables the delay.",
82 : : &post_planning_lock_id,
83 : : 0,
84 : : 0, INT_MAX,
85 : : PGC_USERSET,
86 : : 0,
87 : : NULL,
88 : : NULL,
89 : : NULL);
90 : :
1345 91 : 2 : MarkGUCPrefixReserved("delay_execution");
92 : :
93 : : /* Install our hook */
1908 94 : 2 : prev_planner_hook = planner_hook;
95 : 2 : planner_hook = delay_execution_planner;
96 : 2 : }
|