From 33f6bd9145c45a1090dbfaa018d7025363b35bbc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E4=B8=80=E6=8C=83?= <yizhi.fzh@alibaba-inc.com>
Date: Thu, 6 Aug 2020 23:38:08 +0800
Subject: [PATCH v2] delay_execution used for concurrency case simulation

---
 contrib/delay_execution/Makefile          | 18 +++++
 contrib/delay_execution/delay_execution.c | 90 +++++++++++++++++++++++
 2 files changed, 108 insertions(+)
 create mode 100644 contrib/delay_execution/Makefile
 create mode 100644 contrib/delay_execution/delay_execution.c

diff --git a/contrib/delay_execution/Makefile b/contrib/delay_execution/Makefile
new file mode 100644
index 0000000000..d31179fef6
--- /dev/null
+++ b/contrib/delay_execution/Makefile
@@ -0,0 +1,18 @@
+# contrib/delay_execution/Makefile
+
+MODULE_big = delay_execution
+OBJS = \
+	$(WIN32RES) \
+	delay_execution.o
+PGFILEDESC = "delay_execution used for concurrency case simulation"
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/delay_execution
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/contrib/delay_execution/delay_execution.c b/contrib/delay_execution/delay_execution.c
new file mode 100644
index 0000000000..c0e32b6ca2
--- /dev/null
+++ b/contrib/delay_execution/delay_execution.c
@@ -0,0 +1,90 @@
+/*-------------------------------------------------------------------------
+ *
+ * delay_execution.c
+ *
+ *
+ * Copyright (c) 2008-2020, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *	  contrib/delay_execution/delay_execution.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include <limits.h>
+
+#include "fmgr.h"
+#include "nodes/plannodes.h"
+#include "optimizer/planner.h"
+#include "utils/guc.h"
+#include "utils/fmgrprotos.h"
+
+
+PG_MODULE_MAGIC;
+
+/*
+ * Only the lock ID equals customized_lock_id will be used, so that
+ * different sessions can be blocked at different points.
+ */
+static int customized_lock_id = 0;
+
+/* Lock ID starts with 1 */
+static const int64 after_planner_lock_id = 1;
+
+static planner_hook_type prev_planner_hook = NULL;
+
+void _PG_init(void);
+void _PG_fini(void);
+
+
+static void
+delay_execution_advisory_lock_unlock(int64 lock_id)
+{
+	if (lock_id != customized_lock_id)
+		return;
+	DirectFunctionCall1(pg_advisory_lock_int8, Int64GetDatum(lock_id));
+	DirectFunctionCall1(pg_advisory_unlock_int8, Int64GetDatum(lock_id));
+}
+
+
+static PlannedStmt *
+delay_execution_planner(Query *parse, const char *query_string, int cursorOptions,
+					ParamListInfo boundParams)
+{
+	PlannedStmt *result;
+	if (prev_planner_hook)
+		result = prev_planner_hook(parse, query_string, cursorOptions,
+								   boundParams);
+	else
+		result = standard_planner(parse, query_string, cursorOptions,
+								  boundParams);
+	delay_execution_advisory_lock_unlock(after_planner_lock_id);
+	return result;
+}
+
+void
+_PG_init(void)
+{
+	DefineCustomIntVariable("delay_execution.custom_lock_id",
+							"Set the lock ID which will be lock/unlock during execution.",
+							"All locks ID starts with 1, so zero means not lock will be used.",
+							&customized_lock_id,
+							0,
+							0, INT_MAX,
+							PGC_SUSET,
+							0,
+							NULL,
+							NULL,
+							NULL);
+	prev_planner_hook = planner_hook;
+	planner_hook = delay_execution_planner;
+}
+
+
+void
+_PG_fini(void)
+{
+	planner_hook = prev_planner_hook;
+}
-- 
2.21.0

