From dc0577899642da7847e25673bac2ab3b526bdb62 Mon Sep 17 00:00:00 2001
From: houzj <houzj.fnst@cn.fujitsu.com>
Date: Fri, 29 Jan 2021 13:19:41 +0800
Subject: [PATCH 1/2] reloption parallel_dml src

add new tableoption parallel_dml

In addition to guc option, user may want to use parallel 
dml for some specific tables.So add new tableoption 
parallel_dml, let user decide whether to use parallel 
DML for specific table.

The default is false.

---
 src/backend/access/common/reloptions.c | 25 +++++++++++++++++++++----
 src/backend/optimizer/util/clauses.c   | 26 ++++++++++++++++++++++++++
 src/bin/psql/tab-complete.c            |  1 +
 src/include/utils/rel.h                | 10 ++++++++++
 4 files changed, 58 insertions(+), 4 deletions(-)

diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index c687d3e..f30f2fa 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -168,6 +168,15 @@ static relopt_bool boolRelOpts[] =
 		},
 		true
 	},
+	{
+		{
+			"parallel_dml",
+			"Enables \"parallel dml\" feature for this table",
+			RELOPT_KIND_HEAP | RELOPT_KIND_PARTITIONED,
+			ShareUpdateExclusiveLock
+		},
+		false
+	},
 	/* list terminator */
 	{{NULL}}
 };
@@ -1859,7 +1868,9 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
 		{"vacuum_index_cleanup", RELOPT_TYPE_BOOL,
 		offsetof(StdRdOptions, vacuum_index_cleanup)},
 		{"vacuum_truncate", RELOPT_TYPE_BOOL,
-		offsetof(StdRdOptions, vacuum_truncate)}
+		offsetof(StdRdOptions, vacuum_truncate)},
+		{"parallel_dml", RELOPT_TYPE_BOOL,
+		offsetof(StdRdOptions, parallel_dml)}
 	};
 
 	return (bytea *) build_reloptions(reloptions, validate, kind,
@@ -1961,13 +1972,19 @@ build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
 bytea *
 partitioned_table_reloptions(Datum reloptions, bool validate)
 {
+	static const relopt_parse_elt tab[] = {
+		{"parallel_dml", RELOPT_TYPE_BOOL,
+		offsetof(StdRdOptions, parallel_dml)}
+	};
+
 	/*
-	 * There are no options for partitioned tables yet, but this is able to do
-	 * some validation.
+	 * The only option for partitioned tables works for heap too,
+	 * so we temporarily store it in the same struct as heap.
 	 */
 	return (bytea *) build_reloptions(reloptions, validate,
 									  RELOPT_KIND_PARTITIONED,
-									  0, NULL, 0);
+									  sizeof(StdRdOptions),
+									  tab, lengthof(tab));
 }
 
 /*
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 02a7e05..9d4b100 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -570,6 +570,32 @@ max_parallel_hazard(Query *parse)
 	context.max_hazard = PROPARALLEL_SAFE;
 	context.max_interesting = PROPARALLEL_UNSAFE;
 	context.safe_param_ids = NIL;
+
+	if (IsModifySupportedInParallelMode(parse->commandType))
+	{
+		Relation		rel;
+		RangeTblEntry  *rte;
+
+		rte = rt_fetch(parse->resultRelation, parse->rtable);
+		rel = table_open(rte->relid, NoLock);
+
+		/*
+		 * Check if parallel_dml is enabled for the target table,
+		 * if not, skip the safety checks and return PARALLEL_UNSAFE.
+		 *
+		 * (Note: if target table is partitioned, we just check the
+		 * option of parent table and ignore the option values for its child)
+		 */
+		if(!RelationGetParallelDML(rel, false))
+		{
+			table_close(rel, NoLock);
+			return PROPARALLEL_UNSAFE;
+		}
+
+		table_close(rel, NoLock);
+	}
+
+
 	(void) max_parallel_hazard_walker((Node *) parse, &context);
 
 	/*
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 17f7265..38f5b1e 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1110,6 +1110,7 @@ static const char *const table_storage_parameters[] = {
 	"autovacuum_vacuum_threshold",
 	"fillfactor",
 	"log_autovacuum_min_duration",
+	"parallel_dml",
 	"parallel_workers",
 	"toast.autovacuum_enabled",
 	"toast.autovacuum_freeze_max_age",
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 2a41a00..9dc1ab8 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -307,6 +307,7 @@ typedef struct StdRdOptions
 	int			parallel_workers;	/* max number of parallel workers */
 	bool		vacuum_index_cleanup;	/* enables index vacuuming and cleanup */
 	bool		vacuum_truncate;	/* enables vacuum to truncate a relation */
+	bool		parallel_dml;	/* enable parallel table-modification */
 } StdRdOptions;
 
 #define HEAP_MIN_FILLFACTOR			10
@@ -362,6 +363,15 @@ typedef struct StdRdOptions
 	((relation)->rd_options ? \
 	 ((StdRdOptions *) (relation)->rd_options)->parallel_workers : (defaultpw))
 
+/*
+ * RelationGetParallelDML
+ *		Returns the relation's parallel_dml reloption setting.
+ *		Note multiple eval of argument!
+ */
+#define RelationGetParallelDML(relation, defaultpd) \
+	((relation)->rd_options ? \
+	 ((StdRdOptions *) (relation)->rd_options)->parallel_dml : (defaultpd))
+
 /* ViewOptions->check_option values */
 typedef enum ViewOptCheckOption
 {
-- 
2.7.2.windows.1

