postgresql/src/test/modules/delay_execution/delay_execution.c

96 lines
2.7 KiB
C

/*-------------------------------------------------------------------------
*
* delay_execution.c
* Test module to allow delay between parsing and execution of a query.
*
* The delay is implemented by taking and immediately releasing a specified
* advisory lock. If another process has previously taken that lock, the
* current process will be blocked until the lock is released; otherwise,
* there's no effect. This allows an isolationtester script to reliably
* test behaviors where some specified action happens in another backend
* between parsing and execution of any desired query.
*
* Copyright (c) 2020-2022, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/test/modules/delay_execution/delay_execution.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <limits.h>
#include "optimizer/planner.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/inval.h"
PG_MODULE_MAGIC;
/* GUC: advisory lock ID to use. Zero disables the feature. */
static int post_planning_lock_id = 0;
/* Save previous planner hook user to be a good citizen */
static planner_hook_type prev_planner_hook = NULL;
/* planner_hook function to provide the desired delay */
static PlannedStmt *
delay_execution_planner(Query *parse, const char *query_string,
int cursorOptions, ParamListInfo boundParams)
{
PlannedStmt *result;
/* Invoke the planner, possibly via a previous hook user */
if (prev_planner_hook)
result = prev_planner_hook(parse, query_string, cursorOptions,
boundParams);
else
result = standard_planner(parse, query_string, cursorOptions,
boundParams);
/* If enabled, delay by taking and releasing the specified lock */
if (post_planning_lock_id != 0)
{
DirectFunctionCall1(pg_advisory_lock_int8,
Int64GetDatum((int64) post_planning_lock_id));
DirectFunctionCall1(pg_advisory_unlock_int8,
Int64GetDatum((int64) post_planning_lock_id));
/*
* Ensure that we notice any pending invalidations, since the advisory
* lock functions don't do this.
*/
AcceptInvalidationMessages();
}
return result;
}
/* Module load function */
void
_PG_init(void)
{
/* Set up the GUC to control which lock is used */
DefineCustomIntVariable("delay_execution.post_planning_lock_id",
"Sets the advisory lock ID to be locked/unlocked after planning.",
"Zero disables the delay.",
&post_planning_lock_id,
0,
0, INT_MAX,
PGC_USERSET,
0,
NULL,
NULL,
NULL);
MarkGUCPrefixReserved("delay_execution");
/* Install our hook */
prev_planner_hook = planner_hook;
planner_hook = delay_execution_planner;
}