From b142ffed53fe34baeab67ebcd59a5902bd900afe Mon Sep 17 00:00:00 2001
From: test <test>
Date: Fri, 8 May 2026 02:09:11 +0200
Subject: [PATCH v15 1/5] CREATE-ALTER-TABLE-PARALLEL-DML

Enable users to declare a table's parallel data-modification safety
(SAFE/RESTRICTED/UNSAFE).

Add a table property that represents parallel safety of a table for
DML statement execution.

It may be specified as follows:
CREATE TABLE table_name PARALLEL DML { UNSAFE | RESTRICTED | SAFE };
ALTER TABLE table_name PARALLEL DML { UNSAFE | RESTRICTED | SAFE };

This property is recorded in pg_class's relparallel column as 'u',
'r', or 's', just like pg_proc's proparallel.
The default is UNSAFE.

The planner assumes that all of the table, its descendant partitions,
and their ancillary objects have, at worst, the specified parallel
safety. The user is responsible for its correctness.
---
 src/backend/bootstrap/bootparse.y             |   3 +
 src/backend/catalog/heap.c                    |   7 +-
 src/backend/catalog/index.c                   |   2 +
 src/backend/catalog/toasting.c                |   1 +
 src/backend/commands/createas.c               |   1 +
 src/backend/commands/repack.c                 |   1 +
 src/backend/commands/sequence.c               |   1 +
 src/backend/commands/tablecmds.c              | 101 ++++++++++++++
 src/backend/commands/typecmds.c               |   1 +
 src/backend/commands/view.c                   |   1 +
 src/backend/parser/gram.y                     |  65 ++++++---
 src/backend/utils/cache/relcache.c            |   7 +-
 src/bin/pg_dump/pg_dump.c                     |  39 ++++++
 src/bin/pg_dump/pg_dump.h                     |   1 +
 src/bin/psql/describe.c                       |  72 +++++++++-
 src/include/catalog/heap.h                    |   2 +
 src/include/catalog/pg_class.h                |   3 +
 src/include/nodes/parsenodes.h                |   2 +
 src/include/nodes/primnodes.h                 |   1 +
 src/include/parser/kwlist.h                   |   1 +
 src/include/utils/relcache.h                  |   3 +-
 .../test_ddl_deparse/test_ddl_deparse.c       |   3 +
 src/test/regress/expected/alter_table.out     |   9 ++
 src/test/regress/expected/compression.out     |   8 ++
 src/test/regress/expected/compression_lz4.out |   2 +
 src/test/regress/expected/constraints.out     |  39 ++++++
 src/test/regress/expected/copy2.out           |   1 +
 .../expected/create_property_graph.out        |   8 +-
 src/test/regress/expected/create_table.out    |  14 ++
 .../regress/expected/create_table_like.out    |  13 ++
 src/test/regress/expected/domain.out          |   2 +
 src/test/regress/expected/foreign_data.out    |  42 ++++++
 .../regress/expected/generated_stored.out     |   1 +
 .../regress/expected/generated_virtual.out    |   1 +
 src/test/regress/expected/identity.out        |   1 +
 src/test/regress/expected/inherit.out         |  40 ++++++
 src/test/regress/expected/insert.out          |  13 ++
 src/test/regress/expected/partition_merge.out |   3 +
 src/test/regress/expected/partition_split.out |   8 ++
 src/test/regress/expected/psql.out            | 127 ++++++++++--------
 src/test/regress/expected/publication.out     |   8 ++
 .../regress/expected/replica_identity.out     |   3 +
 src/test/regress/expected/rowsecurity.out     |   1 +
 src/test/regress/expected/rules.out           |   2 +
 src/test/regress/expected/stats_ext.out       |   1 +
 src/test/regress/expected/tablespace.out      |   2 +
 src/test/regress/expected/triggers.out        |   1 +
 src/test/regress/expected/update.out          |   1 +
 48 files changed, 577 insertions(+), 92 deletions(-)

diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 943ff4733d3..3a95178f8b1 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -25,6 +25,7 @@
 #include "catalog/pg_authid.h"
 #include "catalog/pg_class.h"
 #include "catalog/pg_namespace.h"
+#include "catalog/pg_proc.h"
 #include "catalog/pg_tablespace.h"
 #include "catalog/toasting.h"
 #include "commands/defrem.h"
@@ -212,6 +213,7 @@ Boot_CreateStmt:
 												   tupdesc,
 												   RELKIND_RELATION,
 												   RELPERSISTENCE_PERMANENT,
+												   PROPARALLEL_UNSAFE,
 												   shared_relation,
 												   mapped_relation,
 												   true,
@@ -236,6 +238,7 @@ Boot_CreateStmt:
 													  NIL,
 													  RELKIND_RELATION,
 													  RELPERSISTENCE_PERMANENT,
+													  PROPARALLEL_UNSAFE,
 													  shared_relation,
 													  mapped_relation,
 													  ONCOMMIT_NOOP,
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 7678ab13f6a..807819df7b7 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
 			TupleDesc tupDesc,
 			char relkind,
 			char relpersistence,
+			char relparalleldml,
 			bool shared_relation,
 			bool mapped_relation,
 			bool allow_system_table_mods,
@@ -370,7 +371,8 @@ heap_create(const char *relname,
 									 shared_relation,
 									 mapped_relation,
 									 relpersistence,
-									 relkind);
+									 relkind,
+									 relparalleldml);
 
 	/*
 	 * Have the storage manager create the relation's disk file, if needed.
@@ -963,6 +965,7 @@ InsertPgClassTuple(Relation pg_class_desc,
 	values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
 	values[Anum_pg_class_relispopulated - 1] = BoolGetDatum(rd_rel->relispopulated);
 	values[Anum_pg_class_relreplident - 1] = CharGetDatum(rd_rel->relreplident);
+	values[Anum_pg_class_relparalleldml - 1] = CharGetDatum(rd_rel->relparalleldml);
 	values[Anum_pg_class_relispartition - 1] = BoolGetDatum(rd_rel->relispartition);
 	values[Anum_pg_class_relrewrite - 1] = ObjectIdGetDatum(rd_rel->relrewrite);
 	values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
@@ -1145,6 +1148,7 @@ heap_create_with_catalog(const char *relname,
 						 List *cooked_constraints,
 						 char relkind,
 						 char relpersistence,
+						 char relparalleldml,
 						 bool shared_relation,
 						 bool mapped_relation,
 						 OnCommitAction oncommit,
@@ -1333,6 +1337,7 @@ heap_create_with_catalog(const char *relname,
 							   tupdesc,
 							   relkind,
 							   relpersistence,
+							   relparalleldml,
 							   shared_relation,
 							   mapped_relation,
 							   allow_system_table_mods,
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..2a5ba476653 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -48,6 +48,7 @@
 #include "catalog/pg_inherits.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
+#include "catalog/pg_proc.h"
 #include "catalog/pg_tablespace.h"
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
@@ -987,6 +988,7 @@ index_create(Relation heapRelation,
 								indexTupDesc,
 								relkind,
 								relpersistence,
+								PROPARALLEL_UNSAFE,
 								shared_relation,
 								mapped_relation,
 								allow_system_table_mods,
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 4aa52a4bd25..1cd383bf341 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -263,6 +263,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 										   NIL,
 										   RELKIND_TOASTVALUE,
 										   rel->rd_rel->relpersistence,
+										   rel->rd_rel->relparalleldml,
 										   shared_relation,
 										   mapped_relation,
 										   ONCOMMIT_NOOP,
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index 6dbb831ca89..28231470163 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -104,6 +104,7 @@ create_ctas_internal(List *attrList, IntoClause *into)
 	create->options = into->options;
 	create->oncommit = into->onCommit;
 	create->tablespacename = into->tableSpaceName;
+	create->paralleldmlsafety = into->paralleldmlsafety;
 	create->if_not_exists = false;
 	create->accessMethod = into->accessMethod;
 
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 9a199dd9bfb..4c8f22c0de9 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -1169,6 +1169,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod,
 										  NIL,
 										  RELKIND_RELATION,
 										  relpersistence,
+										  OldHeap->rd_rel->relparalleldml,
 										  false,
 										  RelationIsMapped(OldHeap),
 										  ONCOMMIT_NOOP,
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 551667650ba..47afed2bc5e 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -196,6 +196,7 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
 	stmt->options = NIL;
 	stmt->oncommit = ONCOMMIT_NOOP;
 	stmt->tablespacename = NULL;
+	stmt->paralleldmlsafety = NULL;
 	stmt->if_not_exists = seq->if_not_exists;
 
 	address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL, NULL);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 88451c91448..8f28fe059e4 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -783,6 +783,7 @@ static void ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation
 static void ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab,
 								 Relation rel, PartitionCmd *cmd,
 								 AlterTableUtilityContext *context);
+static void ATExecParallelDMLSafety(Relation rel, Node *def);
 static List *collectPartitionIndexExtDeps(List *partitionOids);
 static void applyPartitionIndexExtDeps(Oid newPartOid, List *extDepState);
 static void freePartitionIndexExtDeps(List *extDepState);
@@ -832,6 +833,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	ObjectAddress address;
 	LOCKMODE	parentLockmode;
 	Oid			accessMethodId = InvalidOid;
+	char		relparalleldml = PROPARALLEL_UNSAFE;
 
 	/*
 	 * Truncate relname to appropriate length (probably a waste of time, as
@@ -1113,6 +1115,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 													  old_constraints),
 										  relkind,
 										  stmt->relation->relpersistence,
+										  relparalleldml,
 										  false,
 										  false,
 										  stmt->oncommit,
@@ -1123,6 +1126,35 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 										  InvalidOid,
 										  typaddress);
 
+	/*
+	 * Set parallel safety for DML operations, if specified by the command.
+	 *
+	 * XXX Don't we have reusable parsing for PROPARALLEL_ somewhere?
+	 */
+	if (stmt->paralleldmlsafety != NULL)
+	{
+		if (strcmp(stmt->paralleldmlsafety, "safe") == 0)
+		{
+			if (relkind == RELKIND_FOREIGN_TABLE ||
+				stmt->relation->relpersistence == RELPERSISTENCE_TEMP)
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot perform parallel data modification on relation \"%s\"",
+								relname),
+						 errdetail_relkind_not_supported(relkind)));
+
+			relparalleldml = PROPARALLEL_SAFE;
+		}
+		else if (strcmp(stmt->paralleldmlsafety, "restricted") == 0)
+			relparalleldml = PROPARALLEL_RESTRICTED;
+		else if (strcmp(stmt->paralleldmlsafety, "unsafe") == 0)
+			relparalleldml = PROPARALLEL_UNSAFE;
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_SYNTAX_ERROR),
+					errmsg("parameter \"parallel dml\" must be SAFE, RESTRICTED, or UNSAFE")));
+	}
+
 	/*
 	 * We must bump the command counter to make the newly-created relation
 	 * tuple visible for opening.
@@ -4772,6 +4804,7 @@ AlterTableGetLockLevel(List *cmds)
 			case AT_SetExpression:
 			case AT_DropExpression:
 			case AT_SetCompression:
+			case AT_ParallelDMLSafety:
 				cmd_lockmode = AccessExclusiveLock;
 				break;
 
@@ -5347,6 +5380,11 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
 			/* No command-specific prep needed */
 			pass = AT_PASS_MISC;
 			break;
+		case AT_ParallelDMLSafety:
+			ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
+			/* No command-specific prep needed */
+			pass = AT_PASS_MISC;
+			break;
 		default:				/* oops */
 			elog(ERROR, "unrecognized alter table type: %d",
 				 (int) cmd->subtype);
@@ -5759,6 +5797,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab,
 			ATExecSplitPartition(wqueue, tab, rel, (PartitionCmd *) cmd->def,
 								 context);
 			break;
+		case AT_ParallelDMLSafety:
+			ATExecParallelDMLSafety(rel, cmd->def);
+			break;
 		default:				/* oops */
 			elog(ERROR, "unrecognized alter table type: %d",
 				 (int) cmd->subtype);
@@ -6813,6 +6854,8 @@ alter_table_type_to_string(AlterTableType cmdtype)
 			return "ALTER COLUMN ... DROP IDENTITY";
 		case AT_ReAddStatistics:
 			return NULL;		/* not real grammar */
+		case AT_ParallelDMLSafety:
+			return "PARALLEL DML SAFETY";
 	}
 
 	return NULL;
@@ -22822,6 +22865,7 @@ createPartitionTable(List **wqueue, RangeVar *newPartName,
 										NIL,
 										RELKIND_RELATION,
 										newPartName->relpersistence,
+										parent_relform->relparalleldml,	/* FIXME ok to inherit from parent? */
 										false,
 										false,
 										ONCOMMIT_NOOP,
@@ -23896,3 +23940,60 @@ ATExecSplitPartition(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	/* Restore the userid and security context. */
 	SetUserIdAndSecContext(save_userid, save_sec_context);
 }
+
+/*
+ * ALTER TABLE <name> PARALLEL DML safe/restricted/unsafe
+ */
+static void
+ATExecParallelDMLSafety(Relation rel, Node *def)
+{
+	Relation	pg_class;
+	Oid			relid;
+	HeapTuple	tuple;
+	char		relparallel = PROPARALLEL_SAFE;
+	char	   *parallel = strVal(def);
+
+	if (parallel)
+	{
+		if (strcmp(parallel, "safe") == 0)
+		{
+			/*
+			 * We can't support table modification in a parallel worker if it's a
+			 * foreign table/partition (no FDW API for supporting parallel access) or
+			 * a temporary table.
+			 */
+			if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+				RelationUsesLocalBuffers(rel))
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("cannot perform parallel data modification on relation \"%s\"",
+									RelationGetRelationName(rel)),
+							 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
+
+			relparallel = PROPARALLEL_SAFE;
+		}
+		else if (strcmp(parallel, "restricted") == 0)
+			relparallel = PROPARALLEL_RESTRICTED;
+		else if (strcmp(parallel, "unsafe") == 0)
+			relparallel = PROPARALLEL_UNSAFE;
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_SYNTAX_ERROR),
+					 errmsg("parameter \"parallel dml\" must be SAFE, RESTRICTED, or UNSAFE")));
+	}
+
+	relid = RelationGetRelid(rel);
+
+	pg_class = table_open(RelationRelationId, RowExclusiveLock);
+
+	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
+
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for relation %u", relid);
+
+	((Form_pg_class) GETSTRUCT(tuple))->relparalleldml = relparallel;
+	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
+
+	table_close(pg_class, RowExclusiveLock);
+	heap_freetuple(tuple);
+}
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index cd38e9cddf4..de17b827413 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2596,6 +2596,7 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
 	createStmt->options = NIL;
 	createStmt->oncommit = ONCOMMIT_NOOP;
 	createStmt->tablespacename = NULL;
+	createStmt->paralleldmlsafety = NULL;
 	createStmt->if_not_exists = false;
 
 	/*
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 1bd78a4cdf0..817fb6730a2 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -235,6 +235,7 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace,
 		createStmt->options = options;
 		createStmt->oncommit = ONCOMMIT_NOOP;
 		createStmt->tablespacename = NULL;
+		createStmt->paralleldmlsafety = NULL;
 		createStmt->if_not_exists = false;
 
 		/*
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index ff4e1388c55..1025dcbbba1 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -660,6 +660,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <list>		hash_partbound
 %type <defelt>		hash_partbound_elem
 
+%type <str>			OptParallelDMLSafety
+
 %type <node>	json_format_clause
 				json_format_clause_opt
 				json_value_expr
@@ -761,7 +763,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 	DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
 	DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC DESTINATION
-	DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P
+	DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DML DO DOCUMENT_P DOMAIN_P
 	DOUBLE_P DROP
 
 	EACH EDGE ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENFORCED ENUM_P
@@ -3162,6 +3164,14 @@ alter_table_cmd:
 					n->subtype = AT_NoForceRowSecurity;
 					$$ = (Node *) n;
 				}
+			/* ALTER TABLE <name> PARALLEL DML SAFE/RESTRICTED/UNSAFE */
+			| PARALLEL DML ColId
+				{
+					AlterTableCmd *n = makeNode(AlterTableCmd);
+					n->subtype = AT_ParallelDMLSafety;
+					n->def = (Node *)makeString($3);
+					$$ = (Node *)n;
+				}
 			| alter_generic_options
 				{
 					AlterTableCmd *n = makeNode(AlterTableCmd);
@@ -3785,7 +3795,7 @@ copy_generic_opt_arg_list_item:
 
 CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
 			OptInherit OptPartitionSpec table_access_method_clause OptWith
-			OnCommitOption OptTableSpace
+			OnCommitOption OptTableSpace OptParallelDMLSafety
 				{
 					CreateStmt *n = makeNode(CreateStmt);
 
@@ -3800,12 +3810,13 @@ CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
 					n->options = $11;
 					n->oncommit = $12;
 					n->tablespacename = $13;
+					n->paralleldmlsafety = $14;
 					n->if_not_exists = false;
 					$$ = (Node *) n;
 				}
 		| CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name '('
 			OptTableElementList ')' OptInherit OptPartitionSpec table_access_method_clause
-			OptWith OnCommitOption OptTableSpace
+			OptWith OnCommitOption OptTableSpace OptParallelDMLSafety
 				{
 					CreateStmt *n = makeNode(CreateStmt);
 
@@ -3820,12 +3831,13 @@ CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
 					n->options = $14;
 					n->oncommit = $15;
 					n->tablespacename = $16;
+					n->paralleldmlsafety = $17;
 					n->if_not_exists = true;
 					$$ = (Node *) n;
 				}
 		| CREATE OptTemp TABLE qualified_name OF any_name
 			OptTypedTableElementList OptPartitionSpec table_access_method_clause
-			OptWith OnCommitOption OptTableSpace
+			OptWith OnCommitOption OptTableSpace OptParallelDMLSafety
 				{
 					CreateStmt *n = makeNode(CreateStmt);
 
@@ -3841,12 +3853,13 @@ CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
 					n->options = $10;
 					n->oncommit = $11;
 					n->tablespacename = $12;
+					n->paralleldmlsafety = $13;
 					n->if_not_exists = false;
 					$$ = (Node *) n;
 				}
 		| CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name OF any_name
 			OptTypedTableElementList OptPartitionSpec table_access_method_clause
-			OptWith OnCommitOption OptTableSpace
+			OptWith OnCommitOption OptTableSpace OptParallelDMLSafety
 				{
 					CreateStmt *n = makeNode(CreateStmt);
 
@@ -3862,12 +3875,14 @@ CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
 					n->options = $13;
 					n->oncommit = $14;
 					n->tablespacename = $15;
+					n->paralleldmlsafety = $16;
 					n->if_not_exists = true;
 					$$ = (Node *) n;
 				}
 		| CREATE OptTemp TABLE qualified_name PARTITION OF qualified_name
 			OptTypedTableElementList PartitionBoundSpec OptPartitionSpec
 			table_access_method_clause OptWith OnCommitOption OptTableSpace
+			OptParallelDMLSafety
 				{
 					CreateStmt *n = makeNode(CreateStmt);
 
@@ -3883,12 +3898,14 @@ CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
 					n->options = $12;
 					n->oncommit = $13;
 					n->tablespacename = $14;
+					n->paralleldmlsafety = $15;
 					n->if_not_exists = false;
 					$$ = (Node *) n;
 				}
 		| CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name PARTITION OF
 			qualified_name OptTypedTableElementList PartitionBoundSpec OptPartitionSpec
 			table_access_method_clause OptWith OnCommitOption OptTableSpace
+			OptParallelDMLSafety
 				{
 					CreateStmt *n = makeNode(CreateStmt);
 
@@ -3904,6 +3921,7 @@ CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
 					n->options = $15;
 					n->oncommit = $16;
 					n->tablespacename = $17;
+					n->paralleldmlsafety = $18;
 					n->if_not_exists = true;
 					$$ = (Node *) n;
 				}
@@ -4855,6 +4873,10 @@ OptTableSpace:   TABLESPACE name					{ $$ = $2; }
 			| /*EMPTY*/								{ $$ = NULL; }
 		;
 
+OptParallelDMLSafety:   PARALLEL DML name			{ $$ = $3; }
+			| /*EMPTY*/								{ $$ = NULL; }
+		;
+
 OptConsTableSpace:   USING INDEX TABLESPACE name	{ $$ = $4; }
 			| /*EMPTY*/								{ $$ = NULL; }
 		;
@@ -5010,7 +5032,7 @@ CreateAsStmt:
 
 create_as_target:
 			qualified_name opt_column_list table_access_method_clause
-			OptWith OnCommitOption OptTableSpace
+			OptWith OnCommitOption OptTableSpace OptParallelDMLSafety
 				{
 					$$ = makeNode(IntoClause);
 					$$->rel = $1;
@@ -5019,6 +5041,7 @@ create_as_target:
 					$$->options = $4;
 					$$->onCommit = $5;
 					$$->tableSpaceName = $6;
+					$$->paralleldmlsafety = $7;
 					$$->viewQuery = NULL;
 					$$->skipData = false;		/* might get changed later */
 				}
@@ -5845,7 +5868,7 @@ AlterForeignServerStmt: ALTER SERVER name foreign_server_version alter_generic_o
 CreateForeignTableStmt:
 		CREATE FOREIGN TABLE qualified_name
 			'(' OptTableElementList ')'
-			OptInherit SERVER name create_generic_options
+			OptInherit OptParallelDMLSafety SERVER name create_generic_options
 				{
 					CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
 
@@ -5858,15 +5881,16 @@ CreateForeignTableStmt:
 					n->base.options = NIL;
 					n->base.oncommit = ONCOMMIT_NOOP;
 					n->base.tablespacename = NULL;
+					n->base.paralleldmlsafety = $9;
 					n->base.if_not_exists = false;
 					/* FDW-specific data */
-					n->servername = $10;
-					n->options = $11;
+					n->servername = $11;
+					n->options = $12;
 					$$ = (Node *) n;
 				}
 		| CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name
 			'(' OptTableElementList ')'
-			OptInherit SERVER name create_generic_options
+			OptInherit OptParallelDMLSafety SERVER name create_generic_options
 				{
 					CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
 
@@ -5879,15 +5903,16 @@ CreateForeignTableStmt:
 					n->base.options = NIL;
 					n->base.oncommit = ONCOMMIT_NOOP;
 					n->base.tablespacename = NULL;
+					n->base.paralleldmlsafety = $12;
 					n->base.if_not_exists = true;
 					/* FDW-specific data */
-					n->servername = $13;
-					n->options = $14;
+					n->servername = $14;
+					n->options = $15;
 					$$ = (Node *) n;
 				}
 		| CREATE FOREIGN TABLE qualified_name
 			PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec
-			SERVER name create_generic_options
+			OptParallelDMLSafety SERVER name create_generic_options
 				{
 					CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
 
@@ -5901,15 +5926,16 @@ CreateForeignTableStmt:
 					n->base.options = NIL;
 					n->base.oncommit = ONCOMMIT_NOOP;
 					n->base.tablespacename = NULL;
+					n->base.paralleldmlsafety = $10;
 					n->base.if_not_exists = false;
 					/* FDW-specific data */
-					n->servername = $11;
-					n->options = $12;
+					n->servername = $12;
+					n->options = $13;
 					$$ = (Node *) n;
 				}
 		| CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name
 			PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec
-			SERVER name create_generic_options
+			OptParallelDMLSafety SERVER name create_generic_options
 				{
 					CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
 
@@ -5923,10 +5949,11 @@ CreateForeignTableStmt:
 					n->base.options = NIL;
 					n->base.oncommit = ONCOMMIT_NOOP;
 					n->base.tablespacename = NULL;
+					n->base.paralleldmlsafety = $13;
 					n->base.if_not_exists = true;
 					/* FDW-specific data */
-					n->servername = $14;
-					n->options = $15;
+					n->servername = $15;
+					n->options = $16;
 					$$ = (Node *) n;
 				}
 		;
@@ -18896,6 +18923,7 @@ unreserved_keyword:
 			| DICTIONARY
 			| DISABLE_P
 			| DISCARD
+			| DML
 			| DOCUMENT_P
 			| DOMAIN_P
 			| DOUBLE_P
@@ -19490,6 +19518,7 @@ bare_label_keyword:
 			| DISABLE_P
 			| DISCARD
 			| DISTINCT
+			| DML
 			| DO
 			| DOCUMENT_P
 			| DOMAIN_P
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 0572ab424e7..230ede5fdae 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1951,7 +1951,7 @@ formrdesc(const char *relationName, Oid relationReltype,
 	relation->rd_rel->relallfrozen = 0;
 	relation->rd_rel->relkind = RELKIND_RELATION;
 	relation->rd_rel->relnatts = (int16) natts;
-
+	relation->rd_rel->relparalleldml = PROPARALLEL_UNSAFE;
 	/*
 	 * initialize attribute tuple form
 	 *
@@ -3522,7 +3522,8 @@ RelationBuildLocalRelation(const char *relname,
 						   bool shared_relation,
 						   bool mapped_relation,
 						   char relpersistence,
-						   char relkind)
+						   char relkind,
+						   char relparalleldml)
 {
 	Relation	rel;
 	MemoryContext oldcxt;
@@ -3681,6 +3682,8 @@ RelationBuildLocalRelation(const char *relname,
 	else
 		rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
 
+	rel->rd_rel->relparalleldml = relparalleldml;
+
 	/*
 	 * Insert relation physical and logical identifiers (OIDs) into the right
 	 * places.  For a mapped relation, we set relfilenumber to zero and rely
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d56dcc701ce..80451b2c330 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -7306,6 +7306,7 @@ getTables(Archive *fout, int *numTables)
 	int			i_relpersistence;
 	int			i_relispopulated;
 	int			i_relreplident;
+	int			i_relparalleldml;
 	int			i_relrowsec;
 	int			i_relforcerowsec;
 	int			i_relfrozenxid;
@@ -7392,6 +7393,13 @@ getTables(Archive *fout, int *numTables)
 		appendPQExpBufferStr(query,
 							 "'d' AS relreplident, ");
 
+	if (fout->remoteVersion >= 190000)
+		appendPQExpBufferStr(query,
+							 "c.relparalleldml, ");
+	else
+		appendPQExpBufferStr(query,
+							 "'u' AS relparalleldml, ");
+
 	if (fout->remoteVersion >= 90500)
 		appendPQExpBufferStr(query,
 							 "c.relrowsecurity, c.relforcerowsecurity, ");
@@ -7531,6 +7539,7 @@ getTables(Archive *fout, int *numTables)
 	i_relpersistence = PQfnumber(res, "relpersistence");
 	i_relispopulated = PQfnumber(res, "relispopulated");
 	i_relreplident = PQfnumber(res, "relreplident");
+	i_relparalleldml = PQfnumber(res, "relparalleldml");
 	i_relrowsec = PQfnumber(res, "relrowsecurity");
 	i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
 	i_relfrozenxid = PQfnumber(res, "relfrozenxid");
@@ -7609,6 +7618,7 @@ getTables(Archive *fout, int *numTables)
 		tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
 		tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
 		tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
+		tblinfo[i].relparalleldml = *(PQgetvalue(res, i, i_relparalleldml));
 		tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
 		tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
 		tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
@@ -18183,6 +18193,35 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
 		}
 	}
 
+	/*
+	 * dump information about parallel safety for DML operations
+	 */
+	if (tbinfo->relkind == RELKIND_RELATION ||
+		tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
+		tbinfo->relkind == RELKIND_FOREIGN_TABLE)
+	{
+		appendPQExpBuffer(q, "\nALTER %sTABLE %s PARALLEL DML ",
+						tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
+						qualrelname);
+
+		switch (tbinfo->relparalleldml)
+		{
+			case 's':
+				appendPQExpBuffer(q, "SAFE;\n");
+				break;
+			case 'r':
+				appendPQExpBuffer(q, "RESTRICTED;\n");
+				break;
+			case 'u':
+				appendPQExpBuffer(q, "UNSAFE;\n");
+				break;
+			default:
+				/* should not reach here */
+				appendPQExpBuffer(q, "UNSAFE;\n");
+				break;
+		}
+	}
+
 	if (tbinfo->forcerowsec)
 		appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
 						  qualrelname);
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 5a6726d8b12..d2f567f7472 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -311,6 +311,7 @@ typedef struct _tableInfo
 	char		relpersistence; /* relation persistence */
 	bool		relispopulated; /* relation is populated */
 	char		relreplident;	/* replica identifier */
+	char		relparalleldml; /* parallel safety of dml on the relation */
 	char	   *reltablespace;	/* relation tablespace */
 	char	   *reloptions;		/* options specified by WITH (...) */
 	char	   *checkoption;	/* WITH CHECK OPTION, if any */
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index e1449654f96..8294da889e8 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -1633,6 +1633,7 @@ describeOneTableDetails(const char *schemaname,
 		char	   *reloftype;
 		char		relpersistence;
 		char		relreplident;
+		char		relparalleldml;
 		char	   *relam;
 	}			tableinfo;
 	bool		show_column_details = false;
@@ -1648,7 +1649,25 @@ describeOneTableDetails(const char *schemaname,
 	/* Get general table info */
 	printfPQExpBuffer(&buf, "/* %s */\n",
 					  _("Get general information about one relation"));
-	if (pset.sversion >= 120000)
+	if (pset.sversion >= 190000)
+	{
+		printfPQExpBuffer(&buf,
+						  "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
+						  "c.relhastriggers, c.relrowsecurity, c.relforcerowsecurity, "
+						  "false AS relhasoids, c.relispartition, %s, c.reltablespace, "
+						  "CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
+						  "c.relpersistence, c.relreplident, am.amname, c.relparalleldml\n"
+						  "FROM pg_catalog.pg_class c\n "
+						  "LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
+						  "LEFT JOIN pg_catalog.pg_am am ON (c.relam = am.oid)\n"
+						  "WHERE c.oid = '%s';",
+						  (verbose ?
+						   "pg_catalog.array_to_string(c.reloptions || "
+						   "array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
+						   : "''"),
+						  oid);
+	}
+	else if (pset.sversion >= 120000)
 	{
 		appendPQExpBuffer(&buf,
 						  "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
@@ -1768,6 +1787,8 @@ describeOneTableDetails(const char *schemaname,
 			NULL : pg_strdup(PQgetvalue(res, 0, 14));
 	else
 		tableinfo.relam = NULL;
+	tableinfo.relparalleldml = (pset.sversion >= 190000) ?
+		*(PQgetvalue(res, 0, 15)) : 0;
 	PQclear(res);
 	res = NULL;
 
@@ -3830,6 +3851,20 @@ describeOneTableDetails(const char *schemaname,
 			printfPQExpBuffer(&buf, _("Access method: %s"), tableinfo.relam);
 			printTableAddFooter(&cont, buf.data);
 		}
+
+		if (verbose &&
+			(tableinfo.relkind == RELKIND_RELATION ||
+			 tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
+			 tableinfo.relkind == RELKIND_FOREIGN_TABLE) &&
+			 tableinfo.relparalleldml != 0)
+		{
+			printfPQExpBuffer(&buf, _("Parallel DML: %s"),
+							  (tableinfo.relparalleldml == PROPARALLEL_UNSAFE) ? "unsafe" :
+							  (tableinfo.relparalleldml == PROPARALLEL_RESTRICTED) ? "restricted" :
+							  (tableinfo.relparalleldml == PROPARALLEL_SAFE) ? "safe" :
+							  "???");
+			printTableAddFooter(&cont, buf.data);
+		}
 	}
 
 	/* reloptions, if verbose */
@@ -4249,7 +4284,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 	PGresult   *res;
 	printQueryOpt myopt = pset.popt;
 	int			cols_so_far;
-	bool		translate_columns[] = {false, false, true, false, false, false, false, false, false};
+	bool		translate_columns[] = {false, false, true, false, false, false, false, false, false, false};
 
 	/* Count the number of explicitly-requested relation types */
 	ntypes = showTables + showIndexes + showViews + showMatViews +
@@ -4317,11 +4352,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 						  gettext_noop("unlogged"),
 						  gettext_noop("Persistence"));
 		translate_columns[cols_so_far] = true;
-
-		/*
-		 * We don't bother to count cols_so_far below here, as there's no need
-		 * to; this might change with future additions to the output columns.
-		 */
+		cols_so_far++;
 
 		/*
 		 * Access methods exist for tables, materialized views and indexes.
@@ -4329,9 +4360,36 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 		 */
 		if (pset.sversion >= 120000 && !pset.hide_tableam &&
 			(showTables || showMatViews || showIndexes))
+		{
 			appendPQExpBuffer(&buf,
 							  ",\n  am.amname as \"%s\"",
 							  gettext_noop("Access method"));
+			cols_so_far++;
+		}
+
+		/*
+		 * Show whether the data in the relation is unsafe('u'),
+		 * restricted('r'), or safe('s') can be modified in parallel mode.
+		 * This has been introduced in PostgreSQL 15 for tables.
+		 */
+		if (pset.sversion >= 150000)
+		{
+			appendPQExpBuffer(&buf,
+							  ",\n  CASE c.relparalleldml "
+							  "WHEN " CppAsString2(PROPARALLEL_UNSAFE) " THEN '%s' "
+							  "WHEN " CppAsString2(PROPARALLEL_RESTRICTED) " THEN '%s' "
+							  "WHEN " CppAsString2(PROPARALLEL_SAFE) " THEN '%s' END as \"%s\"",
+							  gettext_noop("unsafe"),
+							  gettext_noop("restricted"),
+							  gettext_noop("safe"),
+							  gettext_noop("Parallel DML"));
+			translate_columns[cols_so_far] = true;
+		}
+
+		/*
+		 * We don't bother to count cols_so_far below here, as there's no need
+		 * to; this might change with future additions to the output columns.
+		 */
 
 		appendPQExpBuffer(&buf,
 						  ",\n  pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as \"%s\""
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index 6c9ac812aa0..42b090c172e 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -57,6 +57,7 @@ extern Relation heap_create(const char *relname,
 							TupleDesc tupDesc,
 							char relkind,
 							char relpersistence,
+							char relparalleldml,
 							bool shared_relation,
 							bool mapped_relation,
 							bool allow_system_table_mods,
@@ -76,6 +77,7 @@ extern Oid	heap_create_with_catalog(const char *relname,
 									 List *cooked_constraints,
 									 char relkind,
 									 char relpersistence,
+									 char relparalleldml,
 									 bool shared_relation,
 									 bool mapped_relation,
 									 OnCommitAction oncommit,
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index c4af599dc90..ab781af40e3 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -121,6 +121,9 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
 	/* see REPLICA_IDENTITY_xxx constants */
 	char		relreplident BKI_DEFAULT(n);
 
+	/* parallel safety of the dml on the relation */
+	char		relparalleldml BKI_DEFAULT(u);
+
 	/* is relation a partition? */
 	bool		relispartition BKI_DEFAULT(f);
 
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 91377a6cde3..5ded0205e02 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2589,6 +2589,7 @@ typedef enum AlterTableType
 	AT_SetIdentity,				/* SET identity column options */
 	AT_DropIdentity,			/* DROP IDENTITY */
 	AT_ReAddStatistics,			/* internal to commands/tablecmds.c */
+	AT_ParallelDMLSafety,		/* PARALLEL DML SAFE/RESTRICTED/UNSAFE */
 } AlterTableType;
 
 typedef struct AlterTableCmd	/* one subcommand of an ALTER TABLE */
@@ -2869,6 +2870,7 @@ typedef struct CreateStmt
 	OnCommitAction oncommit;	/* what do we do at COMMIT? */
 	char	   *tablespacename; /* table space to use, or NULL */
 	char	   *accessMethod;	/* table access method */
+	char	   *paralleldmlsafety; /* parallel dml safety */
 	bool		if_not_exists;	/* just do nothing if it already exists? */
 } CreateStmt;
 
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 7977ee24783..2039df0371b 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -167,6 +167,7 @@ typedef struct IntoClause
 	List	   *options;		/* options from WITH clause */
 	OnCommitAction onCommit;	/* what do we do at COMMIT? */
 	char	   *tableSpaceName; /* table space to use, or NULL */
+	char	   *paralleldmlsafety; /* parallel dml safety */
 	/* materialized view's SELECT query */
 	struct Query *viewQuery pg_node_attr(query_jumble_ignore);
 	bool		skipData;		/* true for WITH NO DATA */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 51ead54f015..eb23bf647e6 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -142,6 +142,7 @@ PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("dml", DML, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("do", DO, RESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, BARE_LABEL)
diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
index 89c27aa1529..a035e30cc59 100644
--- a/src/include/utils/relcache.h
+++ b/src/include/utils/relcache.h
@@ -121,7 +121,8 @@ extern Relation RelationBuildLocalRelation(const char *relname,
 										   bool shared_relation,
 										   bool mapped_relation,
 										   char relpersistence,
-										   char relkind);
+										   char relkind,
+										   char relparalleldml);
 
 /*
  * Routines to manage assignment of new relfilenumber to a relation
diff --git a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
index 64a1dfa9f79..8db1be6cf7b 100644
--- a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
+++ b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
@@ -285,6 +285,9 @@ get_altertable_subcmdinfo(PG_FUNCTION_ARGS)
 			case AT_NoForceRowSecurity:
 				strtype = "NO FORCE ROW SECURITY";
 				break;
+			case AT_ParallelDMLSafety:
+				strtype = "PARALLEL DML SAFETY";
+				break;
 			case AT_GenericOptions:
 				strtype = "SET OPTIONS";
 				break;
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 6dd22be0e8d..e76b369c80b 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -1226,6 +1226,7 @@ Indexes:
     "atnnpart1_pkey" PRIMARY KEY, btree (id)
 Not-null constraints:
     "another_constr" NOT NULL "id" (inherited)
+Parallel DML: unsafe
 
                  Index "public.atnnpart1_pkey"
  Column |  Type   | Key? | Definition | Storage | Stats target 
@@ -1243,6 +1244,7 @@ Not-null constraints:
     "dummy_constr" NOT NULL "id" NOT VALID
 Partitions:
     atnnpart1 FOR VALUES IN (1)
+Parallel DML: unsafe
 
 BEGIN;
 ALTER TABLE atnnparted VALIDATE CONSTRAINT dummy_constr;
@@ -1258,6 +1260,7 @@ Indexes:
     "atnnpart1_pkey" PRIMARY KEY, btree (id)
 Not-null constraints:
     "another_constr" NOT NULL "id" (inherited)
+Parallel DML: unsafe
 
                  Index "public.atnnpart1_pkey"
  Column |  Type   | Key? | Definition | Storage | Stats target 
@@ -1275,6 +1278,7 @@ Not-null constraints:
     "dummy_constr" NOT NULL "id"
 Partitions:
     atnnpart1 FOR VALUES IN (1)
+Parallel DML: unsafe
 
 ROLLBACK;
 -- leave a table in this state for the pg_upgrade test
@@ -2383,6 +2387,7 @@ alter table test_storage alter column a set storage external;
  b      | integer |           |          | random()::integer | plain    |              | 
 Indexes:
     "test_storage_idx" btree (b, a)
+Parallel DML: unsafe
 
 \d+ test_storage_idx
                 Index "public.test_storage_idx"
@@ -3992,6 +3997,7 @@ Not-null constraints:
     "atnotnull1_a_not_null" NOT NULL "a"
     "atnotnull1_b_not_null" NOT NULL "b"
     "atnotnull1_c_not_null" NOT NULL "c"
+Parallel DML: unsafe
 
 -- cannot drop column that is part of the partition key
 CREATE TABLE partitioned (
@@ -4504,6 +4510,7 @@ ALTER TABLE range_parted2 DETACH PARTITION part_rp CONCURRENTLY;
  a      | integer |           |          |         | plain   |              | 
 Partition key: RANGE (a)
 Number of partitions: 0
+Parallel DML: unsafe
 
 DROP TABLE range_parted2;
 -- Test that hash partitions continue to work after they're concurrently
@@ -4558,6 +4565,7 @@ Check constraints:
     "check_b" CHECK (b <> 'zz'::bpchar)
 Not-null constraints:
     "list_parted2_b_not_null" NOT NULL "b"
+Parallel DML: unsafe
 
 -- It's alright though, if no partitions are yet created
 CREATE TABLE parted_no_parts (a int) PARTITION BY LIST (a);
@@ -4870,6 +4878,7 @@ alter table alter1.t1 set schema alter2;
  a      | integer |           |          |         | plain   |              | 
 Included in publications:
     "pub1"
+Parallel DML: unsafe
 
 drop publication pub1;
 drop schema alter1 cascade;
diff --git a/src/test/regress/expected/compression.out b/src/test/regress/expected/compression.out
index 09f198149aa..816e3b1109d 100644
--- a/src/test/regress/expected/compression.out
+++ b/src/test/regress/expected/compression.out
@@ -16,6 +16,7 @@ INSERT INTO cmdata VALUES(repeat('1234567890', 1000));
  f1     | text |           |          |         | extended | pglz        |              | 
 Indexes:
     "idx" btree (f1)
+Parallel DML: unsafe
 
 -- verify stored compression method in the data
 SELECT pg_column_compression(f1) FROM cmdata;
@@ -38,6 +39,7 @@ SELECT * INTO cmmove1 FROM cmdata;
  Column | Type | Collation | Nullable | Default | Storage  | Compression | Stats target | Description 
 --------+------+-----------+----------+---------+----------+-------------+--------------+-------------
  f1     | text |           |          |         | extended |             |              | 
+Parallel DML: unsafe
 
 SELECT pg_column_compression(f1) FROM cmmove1;
  pg_column_compression 
@@ -73,6 +75,7 @@ CREATE TABLE cmdata2 (f1 int);
  Column |  Type   | Collation | Nullable | Default | Storage | Compression | Stats target | Description 
 --------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
  f1     | integer |           |          |         | plain   |             |              | 
+Parallel DML: unsafe
 
 ALTER TABLE cmdata2 ALTER COLUMN f1 TYPE varchar;
 \d+ cmdata2
@@ -80,6 +83,7 @@ ALTER TABLE cmdata2 ALTER COLUMN f1 TYPE varchar;
  Column |       Type        | Collation | Nullable | Default | Storage  | Compression | Stats target | Description 
 --------+-------------------+-----------+----------+---------+----------+-------------+--------------+-------------
  f1     | character varying |           |          |         | extended |             |              | 
+Parallel DML: unsafe
 
 ALTER TABLE cmdata2 ALTER COLUMN f1 TYPE int USING f1::integer;
 \d+ cmdata2
@@ -87,6 +91,7 @@ ALTER TABLE cmdata2 ALTER COLUMN f1 TYPE int USING f1::integer;
  Column |  Type   | Collation | Nullable | Default | Storage | Compression | Stats target | Description 
 --------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
  f1     | integer |           |          |         | plain   |             |              | 
+Parallel DML: unsafe
 
 --changing column storage should not impact the compression method
 --but the data should not be compressed
@@ -97,6 +102,7 @@ ALTER TABLE cmdata2 ALTER COLUMN f1 SET COMPRESSION pglz;
  Column |       Type        | Collation | Nullable | Default | Storage  | Compression | Stats target | Description 
 --------+-------------------+-----------+----------+---------+----------+-------------+--------------+-------------
  f1     | character varying |           |          |         | extended | pglz        |              | 
+Parallel DML: unsafe
 
 ALTER TABLE cmdata2 ALTER COLUMN f1 SET STORAGE plain;
 \d+ cmdata2
@@ -104,6 +110,7 @@ ALTER TABLE cmdata2 ALTER COLUMN f1 SET STORAGE plain;
  Column |       Type        | Collation | Nullable | Default | Storage | Compression | Stats target | Description 
 --------+-------------------+-----------+----------+---------+---------+-------------+--------------+-------------
  f1     | character varying |           |          |         | plain   | pglz        |              | 
+Parallel DML: unsafe
 
 INSERT INTO cmdata2 VALUES (repeat('123456789', 800));
 SELECT pg_column_compression(f1) FROM cmdata2;
@@ -131,6 +138,7 @@ ALTER TABLE cmdata2 ALTER COLUMN f1 SET COMPRESSION default;
  Column |       Type        | Collation | Nullable | Default | Storage | Compression | Stats target | Description 
 --------+-------------------+-----------+----------+---------+---------+-------------+--------------+-------------
  f1     | character varying |           |          |         | plain   |             |              | 
+Parallel DML: unsafe
 
 DROP TABLE cmdata2;
 -- VACUUM FULL does not recompress
diff --git a/src/test/regress/expected/compression_lz4.out b/src/test/regress/expected/compression_lz4.out
index 068dd7c3674..5bd60d12ce4 100644
--- a/src/test/regress/expected/compression_lz4.out
+++ b/src/test/regress/expected/compression_lz4.out
@@ -46,6 +46,7 @@ SELECT * INTO cmmove1 FROM cmdata_lz4;
  Column | Type | Collation | Nullable | Default | Storage  | Compression | Stats target | Description 
 --------+------+-----------+----------+---------+----------+-------------+--------------+-------------
  f1     | text |           |          |         | extended |             |              | 
+Parallel DML: unsafe
 
 SELECT pg_column_compression(f1) FROM cmmove1;
  pg_column_compression 
@@ -61,6 +62,7 @@ CREATE TABLE cmdata2 (LIKE cmdata_lz4 INCLUDING COMPRESSION);
  Column | Type | Collation | Nullable | Default | Storage  | Compression | Stats target | Description 
 --------+------+-----------+----------+---------+----------+-------------+--------------+-------------
  f1     | text |           |          |         | extended | lz4         |              | 
+Parallel DML: unsafe
 
 DROP TABLE cmdata2;
 -- copy to existing table
diff --git a/src/test/regress/expected/constraints.out b/src/test/regress/expected/constraints.out
index 728ef2fd17e..0f0c8878439 100644
--- a/src/test/regress/expected/constraints.out
+++ b/src/test/regress/expected/constraints.out
@@ -929,6 +929,7 @@ CREATE TABLE notnull_tbl1 (a INTEGER NOT NULL NOT NULL);
  a      | integer |           | not null |         | plain   |              | 
 Not-null constraints:
     "notnull_tbl1_a_not_null" NOT NULL "a"
+Parallel DML: unsafe
 
 -- specifying an existing constraint is a no-op
 ALTER TABLE notnull_tbl1 ADD CONSTRAINT notnull_tbl1_a_not_null NOT NULL a;
@@ -943,6 +944,7 @@ DETAIL:  A not-null constraint named "notnull_tbl1_a_not_null" already exists fo
  a      | integer |           | not null |         | plain   |              | 
 Not-null constraints:
     "notnull_tbl1_a_not_null" NOT NULL "a"
+Parallel DML: unsafe
 
 -- duplicate name
 ALTER TABLE notnull_tbl1 ADD COLUMN b INT CONSTRAINT notnull_tbl1_a_not_null NOT NULL;
@@ -954,6 +956,7 @@ ALTER TABLE notnull_tbl1 ALTER a DROP NOT NULL;
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
 --------+---------+-----------+----------+---------+---------+--------------+-------------
  a      | integer |           |          |         | plain   |              | 
+Parallel DML: unsafe
 
 -- SET NOT NULL puts both back
 ALTER TABLE notnull_tbl1 ALTER a SET NOT NULL;
@@ -964,6 +967,7 @@ ALTER TABLE notnull_tbl1 ALTER a SET NOT NULL;
  a      | integer |           | not null |         | plain   |              | 
 Not-null constraints:
     "notnull_tbl1_a_not_null" NOT NULL "a"
+Parallel DML: unsafe
 
 -- Doing it twice doesn't create a redundant constraint
 ALTER TABLE notnull_tbl1 ALTER a SET NOT NULL;
@@ -983,6 +987,7 @@ ALTER TABLE notnull_tbl1 ADD CONSTRAINT foobar NOT NULL a;
  a      | integer |           | not null |         | plain   |              | 
 Not-null constraints:
     "foobar" NOT NULL "a"
+Parallel DML: unsafe
 
 DROP TABLE notnull_tbl1;
 -- Verify that constraint names and NO INHERIT are properly considered when
@@ -999,6 +1004,7 @@ Indexes:
     "notnull_tbl1_pkey" PRIMARY KEY, btree (a)
 Not-null constraints:
     "foo" NOT NULL "a"
+Parallel DML: unsafe
 
 create table notnull_tbl2 (a serial, constraint foo not null a);
 \d+ notnull_tbl2
@@ -1008,6 +1014,7 @@ create table notnull_tbl2 (a serial, constraint foo not null a);
  a      | integer |           | not null | nextval('notnull_tbl2_a_seq'::regclass) | plain   |              | 
 Not-null constraints:
     "foo" NOT NULL "a"
+Parallel DML: unsafe
 
 create table notnull_tbl3 (constraint foo not null a, a int generated by default as identity);
 \d+ notnull_tbl3
@@ -1017,6 +1024,7 @@ create table notnull_tbl3 (constraint foo not null a, a int generated by default
  a      | integer |           | not null | generated by default as identity | plain   |              | 
 Not-null constraints:
     "foo" NOT NULL "a"
+Parallel DML: unsafe
 
 create table notnull_tbl4 (a int not null constraint foo not null);
 \d+ notnull_tbl4
@@ -1026,6 +1034,7 @@ create table notnull_tbl4 (a int not null constraint foo not null);
  a      | integer |           | not null |         | plain   |              | 
 Not-null constraints:
     "foo" NOT NULL "a"
+Parallel DML: unsafe
 
 create table notnull_tbl5 (a int constraint foo not null constraint foo not null);
 \d+ notnull_tbl5
@@ -1035,6 +1044,7 @@ create table notnull_tbl5 (a int constraint foo not null constraint foo not null
  a      | integer |           | not null |         | plain   |              | 
 Not-null constraints:
     "foo" NOT NULL "a"
+Parallel DML: unsafe
 
 create table notnull_tbl6 (like notnull_tbl1, constraint foo not null a);
 \d+ notnull_tbl6
@@ -1044,6 +1054,7 @@ create table notnull_tbl6 (like notnull_tbl1, constraint foo not null a);
  a      | integer |           | not null |         | plain   |              | 
 Not-null constraints:
     "foo" NOT NULL "a"
+Parallel DML: unsafe
 
 drop table notnull_tbl2, notnull_tbl3, notnull_tbl4, notnull_tbl5, notnull_tbl6;
 -- error cases:
@@ -1086,6 +1097,7 @@ CREATE TABLE ATACC2 () INHERITS (ATACC1);
  a      | integer |           |          |         | plain   |              | 
 Inherits:
     atacc1
+Parallel DML: unsafe
 
 DROP TABLE ATACC1, ATACC2;
 CREATE TABLE ATACC1 (a int);
@@ -1098,6 +1110,7 @@ CREATE TABLE ATACC2 () INHERITS (ATACC1);
  a      | integer |           |          |         | plain   |              | 
 Inherits:
     atacc1
+Parallel DML: unsafe
 
 DROP TABLE ATACC1, ATACC2;
 CREATE TABLE ATACC1 (a int);
@@ -1110,6 +1123,7 @@ ALTER TABLE ATACC1 ADD NOT NULL a NO INHERIT;
  a      | integer |           |          |         | plain   |              | 
 Inherits:
     atacc1
+Parallel DML: unsafe
 
 CREATE TABLE ATACC3 (PRIMARY KEY (a)) INHERITS (ATACC1);
 \d+ ATACC3
@@ -1123,6 +1137,7 @@ Not-null constraints:
     "atacc3_a_not_null" NOT NULL "a"
 Inherits:
     atacc1
+Parallel DML: unsafe
 
 DROP TABLE ATACC1, ATACC2, ATACC3;
 -- NOT NULL NO INHERIT is not possible on partitioned tables
@@ -1152,6 +1167,7 @@ Not-null constraints:
     "ditto" NOT NULL "a" (inherited)
 Inherits:
     atacc2
+Parallel DML: unsafe
 
 DROP TABLE ATACC1, ATACC2, ATACC3;
 -- Can't have two constraints with the same name
@@ -1202,6 +1218,7 @@ Not-null constraints:
     "cnn_pk_b_not_null" NOT NULL "b"
 Child tables:
     cnn_pk_child
+Parallel DML: unsafe
 
                                Table "public.cnn_pk_child"
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
@@ -1212,6 +1229,7 @@ Not-null constraints:
     "cnn_pk_b_not_null" NOT NULL "b" (inherited)
 Inherits:
     cnn_pk
+Parallel DML: unsafe
 
 ALTER TABLE cnn_pk DROP CONSTRAINT cnn_primarykey;
 \d+ cnn_pk*
@@ -1224,6 +1242,7 @@ Not-null constraints:
     "cnn_pk_b_not_null" NOT NULL "b"
 Child tables:
     cnn_pk_child
+Parallel DML: unsafe
 
                                Table "public.cnn_pk_child"
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
@@ -1234,6 +1253,7 @@ Not-null constraints:
     "cnn_pk_b_not_null" NOT NULL "b" (inherited)
 Inherits:
     cnn_pk
+Parallel DML: unsafe
 
 DROP TABLE cnn_pk, cnn_pk_child;
 -- As above, but create the primary key ahead of time
@@ -1251,6 +1271,7 @@ Not-null constraints:
     "cnn_pk_b_not_null" NOT NULL "b"
 Child tables:
     cnn_pk_child
+Parallel DML: unsafe
 
                                Table "public.cnn_pk_child"
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
@@ -1261,6 +1282,7 @@ Not-null constraints:
     "cnn_pk_b_not_null" NOT NULL "b" (inherited)
 Inherits:
     cnn_pk
+Parallel DML: unsafe
 
 ALTER TABLE cnn_pk DROP CONSTRAINT cnn_primarykey;
 \d+ cnn_pk*
@@ -1273,6 +1295,7 @@ Not-null constraints:
     "cnn_pk_b_not_null" NOT NULL "b"
 Child tables:
     cnn_pk_child
+Parallel DML: unsafe
 
                                Table "public.cnn_pk_child"
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
@@ -1283,6 +1306,7 @@ Not-null constraints:
     "cnn_pk_b_not_null" NOT NULL "b" (inherited)
 Inherits:
     cnn_pk
+Parallel DML: unsafe
 
 DROP TABLE cnn_pk, cnn_pk_child;
 -- As above, but create the primary key using a UNIQUE index
@@ -1303,6 +1327,7 @@ Not-null constraints:
     "cnn_pk_b_not_null" NOT NULL "b"
 Child tables:
     cnn_pk_child
+Parallel DML: unsafe
 
                                Table "public.cnn_pk_child"
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
@@ -1313,6 +1338,7 @@ Not-null constraints:
     "cnn_pk_b_not_null" NOT NULL "b" (inherited)
 Inherits:
     cnn_pk
+Parallel DML: unsafe
 
 DROP TABLE cnn_pk, cnn_pk_child;
 -- Unique constraints don't give raise to not-null constraints, however.
@@ -1325,6 +1351,7 @@ alter table cnn_uq add unique (a);
  a      | integer |           |          |         | plain   |              | 
 Indexes:
     "cnn_uq_a_key" UNIQUE CONSTRAINT, btree (a)
+Parallel DML: unsafe
 
 drop table cnn_uq;
 create table cnn_uq (a int);
@@ -1337,6 +1364,7 @@ alter table cnn_uq add unique using index cnn_uq_idx;
  a      | integer |           |          |         | plain   |              | 
 Indexes:
     "cnn_uq_idx" UNIQUE CONSTRAINT, btree (a)
+Parallel DML: unsafe
 
 -- can't create a primary key on a noinherit not-null
 create table cnn_pk (a int not null no inherit);
@@ -1375,6 +1403,7 @@ Child tables:
     notnull_tbl4_cld
     notnull_tbl4_cld2
     notnull_tbl4_cld3
+Parallel DML: unsafe
 
 \d+ notnull_tbl4_lk
                               Table "public.notnull_tbl4_lk"
@@ -1383,6 +1412,7 @@ Child tables:
  a      | integer |           | not null |         | plain   |              | 
 Not-null constraints:
     "notnull_tbl4_a_not_null" NOT NULL "a"
+Parallel DML: unsafe
 
 \d+ notnull_tbl4_lk2
                              Table "public.notnull_tbl4_lk2"
@@ -1393,6 +1423,7 @@ Indexes:
     "notnull_tbl4_lk2_pkey" PRIMARY KEY, btree (a) DEFERRABLE INITIALLY DEFERRED
 Not-null constraints:
     "notnull_tbl4_a_not_null" NOT NULL "a"
+Parallel DML: unsafe
 
 \d+ notnull_tbl4_lk3
                              Table "public.notnull_tbl4_lk3"
@@ -1403,6 +1434,7 @@ Indexes:
     "notnull_tbl4_lk3_pkey" PRIMARY KEY, btree (a) DEFERRABLE INITIALLY DEFERRED
 Not-null constraints:
     "a_nn" NOT NULL "a"
+Parallel DML: unsafe
 
 \d+ notnull_tbl4_cld
                              Table "public.notnull_tbl4_cld"
@@ -1413,6 +1445,7 @@ Not-null constraints:
     "notnull_tbl4_a_not_null" NOT NULL "a" (inherited)
 Inherits:
     notnull_tbl4
+Parallel DML: unsafe
 
 \d+ notnull_tbl4_cld2
                              Table "public.notnull_tbl4_cld2"
@@ -1425,6 +1458,7 @@ Not-null constraints:
     "notnull_tbl4_cld2_a_not_null" NOT NULL "a" (local, inherited)
 Inherits:
     notnull_tbl4
+Parallel DML: unsafe
 
 \d+ notnull_tbl4_cld3
                              Table "public.notnull_tbl4_cld3"
@@ -1437,6 +1471,7 @@ Not-null constraints:
     "a_nn" NOT NULL "a" (local, inherited)
 Inherits:
     notnull_tbl4
+Parallel DML: unsafe
 
 -- leave these tables around for pg_upgrade testing
 -- It's possible to remove a constraint from parents without affecting children
@@ -1456,6 +1491,7 @@ Not-null constraints:
     "bnn" NOT NULL "b"
 Inherits:
     notnull_tbl5
+Parallel DML: unsafe
 
 CREATE TABLE notnull_tbl6 (a int CONSTRAINT ann NOT NULL,
 	b int CONSTRAINT bnn NOT NULL, check (a > 0)) PARTITION BY LIST (a);
@@ -1475,6 +1511,7 @@ Check constraints:
 Not-null constraints:
     "ann" NOT NULL "a"
     "bnn" NOT NULL "b"
+Parallel DML: unsafe
 
 -- NOT NULL NOT VALID
 PREPARE get_nnconstraint_info(regclass[]) AS
@@ -1499,6 +1536,7 @@ DETAIL:  Failing row contains (null, 4).
  b      | integer |           |          |         | plain   |              | 
 Not-null constraints:
     "nn" NOT NULL "a" NOT VALID
+Parallel DML: unsafe
 
 -- If we have an invalid constraint, we can't have another
 ALTER TABLE notnull_tbl1 ADD CONSTRAINT nn1 NOT NULL a NOT VALID NO INHERIT;
@@ -1528,6 +1566,7 @@ ERROR:  column "a" of relation "notnull_tbl1" contains null values
  b      | integer |           |          |         | plain   |              | 
 Not-null constraints:
     "nn" NOT NULL "a" NOT VALID
+Parallel DML: unsafe
 
 -- Creating a derived table using LIKE gets the constraint, but it's valid
 CREATE TABLE notnull_tbl1_copy (LIKE notnull_tbl1);
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index 7600e5239d2..dfc9b5e1af3 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -646,6 +646,7 @@ alter table check_con_tbl add check (check_con_function(check_con_tbl.*));
  f1     | integer |           |          |         | plain   |              | 
 Check constraints:
     "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+Parallel DML: unsafe
 
 copy check_con_tbl from stdin;
 NOTICE:  input = {"f1":1}
diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out
index f625524abce..63607adb389 100644
--- a/src/test/regress/expected/create_property_graph.out
+++ b/src/test/regress/expected/create_property_graph.out
@@ -790,10 +790,10 @@ ERROR:  "pg_type" is not a property graph
 (1 row)
 
 \dG+ g1
-                                             List of property graphs
-           Schema            | Name |      Type      |        Owner        | Persistence |  Size   | Description 
------------------------------+------+----------------+---------------------+-------------+---------+-------------
- create_property_graph_tests | g1   | property graph | regress_graph_user1 | permanent   | 0 bytes | a graph
+                                                    List of property graphs
+           Schema            | Name |      Type      |        Owner        | Persistence | Parallel DML |  Size   | Description 
+-----------------------------+------+----------------+---------------------+-------------+--------------+---------+-------------
+ create_property_graph_tests | g1   | property graph | regress_graph_user1 | permanent   | unsafe       | 0 bytes | a graph
 (1 row)
 
 \dGx g1
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index a7a24fa3adc..c816b01bac3 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -322,6 +322,7 @@ Number of partitions: 0
  b      | text    |           |          |         | extended |              | 
 Partition key: RANGE (((a + 1)), substr(b, 1, 5))
 Number of partitions: 0
+Parallel DML: unsafe
 
 INSERT INTO partitioned2 VALUES (1, 'hello');
 ERROR:  no partition of relation "partitioned2" found for row
@@ -335,6 +336,7 @@ CREATE TABLE part2_1 PARTITION OF partitioned2 FOR VALUES FROM (-1, 'aaaaa') TO
  b      | text    |           |          |         | extended |              | 
 Partition of: partitioned2 FOR VALUES FROM ('-1', 'aaaaa') TO (100, 'ccccc')
 Partition constraint: (((a + 1) IS NOT NULL) AND (substr(b, 1, 5) IS NOT NULL) AND (((a + 1) > '-1'::integer) OR (((a + 1) = '-1'::integer) AND (substr(b, 1, 5) >= 'aaaaa'::text))) AND (((a + 1) < 100) OR (((a + 1) = 100) AND (substr(b, 1, 5) < 'ccccc'::text))))
+Parallel DML: unsafe
 
 DROP TABLE partitioned, partitioned2;
 -- check reference to partitioned table's rowtype in partition descriptor
@@ -376,6 +378,7 @@ select * from partitioned where partitioned = '(1,2)'::partitioned;
  b      | integer |           |          |         | plain   |              | 
 Partition of: partitioned FOR VALUES IN ('(1,2)')
 Partition constraint: (((partitioned1.*)::partitioned IS DISTINCT FROM NULL) AND ((partitioned1.*)::partitioned = '(1,2)'::partitioned))
+Parallel DML: unsafe
 
 drop table partitioned;
 -- check that dependencies of partition columns are handled correctly
@@ -436,6 +439,7 @@ Partitions:
     part_p1 FOR VALUES IN (1)
     part_p2 FOR VALUES IN (2)
     part_p3 FOR VALUES IN (3)
+Parallel DML: unsafe
 
 -- forbidden expressions for partition bound with list partitioned table
 CREATE TABLE part_bogus_expr_fail PARTITION OF list_parted FOR VALUES IN (somename);
@@ -887,6 +891,7 @@ Partition of: parted FOR VALUES IN ('b')
 Partition constraint: ((a IS NOT NULL) AND (a = 'b'::text))
 Not-null constraints:
     "part_b_b_not_null" NOT NULL "b" (local, inherited)
+Parallel DML: unsafe
 
 -- Both partition bound and partition key in describe output
 \d+ part_c
@@ -902,6 +907,7 @@ Not-null constraints:
     "part_c_b_not_null" NOT NULL "b" (local, inherited)
 Partitions:
     part_c_1_10 FOR VALUES FROM (1) TO (10)
+Parallel DML: unsafe
 
 -- a level-2 partition's constraint will include the parent's expressions
 \d+ part_c_1_10
@@ -914,6 +920,7 @@ Partition of: part_c FOR VALUES FROM (1) TO (10)
 Partition constraint: ((a IS NOT NULL) AND (a = 'c'::text) AND (b IS NOT NULL) AND (b >= 1) AND (b < 10))
 Not-null constraints:
     "part_c_b_not_null" NOT NULL "b" (inherited)
+Parallel DML: unsafe
 
 -- Show partition count in the parent's describe output
 -- Tempted to include \d+ output listing partitions with bound info but
@@ -948,6 +955,7 @@ CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MI
  c      | integer |           |          |         | plain   |              | 
 Partition of: range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (MAXVALUE, MAXVALUE, MAXVALUE)
 Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL))
+Parallel DML: unsafe
 
 DROP TABLE unbounded_range_part;
 CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (1, MAXVALUE, MAXVALUE);
@@ -960,6 +968,7 @@ CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALU
  c      | integer |           |          |         | plain   |              | 
 Partition of: range_parted4 FOR VALUES FROM (MINVALUE, MINVALUE, MINVALUE) TO (1, MAXVALUE, MAXVALUE)
 Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL) AND (abs(a) <= 1))
+Parallel DML: unsafe
 
 CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, MAXVALUE);
 \d+ range_parted4_2
@@ -971,6 +980,7 @@ CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5
  c      | integer |           |          |         | plain   |              | 
 Partition of: range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, MAXVALUE)
 Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL) AND ((abs(a) > 3) OR ((abs(a) = 3) AND (abs(b) > 4)) OR ((abs(a) = 3) AND (abs(b) = 4) AND (c >= 5))) AND ((abs(a) < 6) OR ((abs(a) = 6) AND (abs(b) <= 7))))
+Parallel DML: unsafe
 
 CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, MAXVALUE);
 \d+ range_parted4_3
@@ -982,6 +992,7 @@ CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, M
  c      | integer |           |          |         | plain   |              | 
 Partition of: range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, MAXVALUE)
 Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL) AND ((abs(a) > 6) OR ((abs(a) = 6) AND (abs(b) >= 8))) AND (abs(a) <= 9))
+Parallel DML: unsafe
 
 DROP TABLE range_parted4;
 -- user-defined operator class in partition key
@@ -1018,6 +1029,7 @@ SELECT obj_description('parted_col_comment'::regclass);
  b      | text    |           |          |         | extended |              | 
 Partition key: LIST (a)
 Number of partitions: 0
+Parallel DML: unsafe
 
 DROP TABLE parted_col_comment;
 -- specifying storage parameters for partitioned tables is not supported
@@ -1034,6 +1046,7 @@ CREATE TABLE arrlp12 PARTITION OF arrlp FOR VALUES IN ('{1}', '{2}');
  a      | integer[] |           |          |         | extended |              | 
 Partition of: arrlp FOR VALUES IN ('{1}', '{2}')
 Partition constraint: ((a IS NOT NULL) AND ((a = '{1}'::integer[]) OR (a = '{2}'::integer[])))
+Parallel DML: unsafe
 
 DROP TABLE arrlp;
 -- partition on boolean column
@@ -1049,6 +1062,7 @@ Partition key: LIST (a)
 Partitions:
     boolspart_f FOR VALUES IN (false)
     boolspart_t FOR VALUES IN (true)
+Parallel DML: unsafe
 
 drop table boolspart;
 -- partitions mixing temporary and permanent relations
diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out
index 76069bde756..4f03ea6fd18 100644
--- a/src/test/regress/expected/create_table_like.out
+++ b/src/test/regress/expected/create_table_like.out
@@ -278,6 +278,7 @@ CREATE TABLE test_like_6c (LIKE test_like_6 INCLUDING ALL);
  b      | text    |           |          |         | extended |              | 
 Statistics objects:
     "public.test_like_6c_expr_stat" ON (a || b) FROM test_like_6c
+Parallel DML: unsafe
 
 DROP TABLE test_like_4, test_like_4a, test_like_4b, test_like_4c, test_like_4d;
 DROP TABLE test_like_5, test_like_5x, test_like_5c;
@@ -358,6 +359,7 @@ CREATE TABLE ctlt12_storage (LIKE ctlt1 INCLUDING STORAGE, LIKE ctlt2 INCLUDING
 Not-null constraints:
     "ctlt1_a_not_null" NOT NULL "a"
     "ctlt2_c_not_null" NOT NULL "c"
+Parallel DML: unsafe
 
 CREATE TABLE ctlt12_comments (LIKE ctlt1 INCLUDING COMMENTS, LIKE ctlt2 INCLUDING COMMENTS);
 \d+ ctlt12_comments
@@ -370,6 +372,7 @@ CREATE TABLE ctlt12_comments (LIKE ctlt1 INCLUDING COMMENTS, LIKE ctlt2 INCLUDIN
 Not-null constraints:
     "ctlt1_a_not_null" NOT NULL "a"
     "ctlt2_c_not_null" NOT NULL "c"
+Parallel DML: unsafe
 
 SELECT conname, description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 'ctlt12_comments'::regclass;
      conname      |  description  
@@ -397,6 +400,7 @@ Not-null constraints:
     "ctlt1_a_not_null" NOT NULL "a" (local, inherited)
 Inherits:
     ctlt1
+Parallel DML: unsafe
 
 SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 'ctlt1_inh'::regclass;
  description 
@@ -424,6 +428,7 @@ Not-null constraints:
 Inherits:
     ctlt1
     ctlt3
+Parallel DML: unsafe
 
 CREATE TABLE ctlt13_like (LIKE ctlt3 INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING COMMENTS INCLUDING STORAGE) INHERITS (ctlt1);
 NOTICE:  merging column "a" with inherited definition
@@ -446,6 +451,7 @@ Not-null constraints:
     "ctlt1_a_not_null" NOT NULL "a" (inherited)
 Inherits:
     ctlt1
+Parallel DML: unsafe
 
 SELECT description FROM pg_description, pg_constraint c WHERE classoid = 'pg_constraint'::regclass AND objoid = c.oid AND c.conrelid = 'ctlt13_like'::regclass;
  description 
@@ -473,6 +479,7 @@ Statistics objects:
     "public.ctlt_all_expr_stat" ON (a || b) FROM ctlt_all
 Not-null constraints:
     "ctlt1_a_not_null" NOT NULL "a"
+Parallel DML: unsafe
 
 SELECT c.relname, objsubid, description FROM pg_description, pg_index i, pg_class c WHERE classoid = 'pg_class'::regclass AND objoid = i.indexrelid AND c.oid = i.indexrelid AND i.indrelid = 'ctlt_all'::regclass ORDER BY c.relname, objsubid;
     relname     | objsubid | description 
@@ -517,6 +524,7 @@ Statistics objects:
     "public.pg_attrdef_expr_stat" ON (a || b) FROM public.pg_attrdef
 Not-null constraints:
     "ctlt1_a_not_null" NOT NULL "a"
+Parallel DML: unsafe
 
 DROP TABLE public.pg_attrdef;
 -- Check that LIKE isn't confused when new table masks the old, either
@@ -543,6 +551,7 @@ Statistics objects:
     "ctl_schema.ctlt1_expr_stat" ON (a || b) FROM ctlt1
 Not-null constraints:
     "ctlt1_a_not_null" NOT NULL "a"
+Parallel DML: unsafe
 
 ROLLBACK;
 DROP TABLE ctlt1, ctlt2, ctlt3, ctlt4, ctlt12_storage, ctlt12_comments, ctlt1_inh, ctlt13_inh, ctlt13_like, ctlt_all, ctla, ctlb CASCADE;
@@ -565,6 +574,7 @@ Check constraints:
 Not-null constraints:
     "noinh_con_copy_b_not_null" NOT NULL "b"
     "noinh_con_copy_c_not_null" NOT NULL "c" NO INHERIT
+Parallel DML: unsafe
 
 SELECT conname, description
 FROM  pg_description, pg_constraint c
@@ -634,6 +644,7 @@ Statistics objects:
 Not-null constraints:
     "ctl_table_a_not_null" NOT NULL "a"
     "ctl_table_d_not_null" NOT NULL "d"
+Parallel DML: unsafe
 
 -- Test EXCLUDING ALL
 CREATE FOREIGN TABLE ctl_foreign_table1(LIKE ctl_table EXCLUDING ALL) SERVER ctl_s0;
@@ -650,6 +661,7 @@ Not-null constraints:
     "ctl_table_a_not_null" NOT NULL "a"
     "ctl_table_d_not_null" NOT NULL "d"
 Server: ctl_s0
+Parallel DML: unsafe
 
 -- \d+ does not report the value of attcompression for a foreign table, so
 -- check separately.
@@ -684,6 +696,7 @@ Not-null constraints:
     "ctl_table_a_not_null" NOT NULL "a"
     "ctl_table_d_not_null" NOT NULL "d"
 Server: ctl_s0
+Parallel DML: unsafe
 
 -- \d+ does not report the value of attcompression for a foreign table, so
 -- check separately.
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 62a48a523a2..3773d505157 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -379,6 +379,7 @@ Rules:
     silly AS
     ON DELETE TO dcomptable DO INSTEAD  UPDATE dcomptable SET d1.r = (dcomptable.d1).r - 1::double precision, d1.i = (dcomptable.d1).i + 1::double precision
   WHERE (dcomptable.d1).i > 0::double precision
+Parallel DML: unsafe
 
 create function makedcomp(r float8, i float8) returns dcomptype
 as 'select row(r, i)' language sql;
@@ -540,6 +541,7 @@ Rules:
     silly AS
     ON DELETE TO dcomptable DO INSTEAD  UPDATE dcomptable SET d1[1].r = dcomptable.d1[1].r - 1::double precision, d1[1].i = dcomptable.d1[1].i + 1::double precision
   WHERE dcomptable.d1[1].i > 0::double precision
+Parallel DML: unsafe
 
 drop table dcomptable;
 drop type comptype cascade;
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index d8e4cb12c3d..2b450f91544 100644
--- a/src/test/regress/expected/foreign_data.out
+++ b/src/test/regress/expected/foreign_data.out
@@ -762,6 +762,7 @@ Not-null constraints:
     "ft1_c1_not_null" NOT NULL "c1"
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
+Parallel DML: unsafe
 
 \det+
                                  List of foreign tables
@@ -891,6 +892,7 @@ Not-null constraints:
     "ft1_c6_not_null" NOT NULL "c6"
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
+Parallel DML: unsafe
 
 -- can't change the column type if it's used elsewhere
 CREATE TABLE use_ft1_column_type (x ft1);
@@ -1447,6 +1449,7 @@ Not-null constraints:
     "fd_pt1_c1_not_null" NOT NULL "c1"
 Child tables:
     ft2, FOREIGN
+Parallel DML: unsafe
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1461,6 +1464,7 @@ Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 Inherits:
     fd_pt1
+Parallel DML: unsafe
 
 DROP FOREIGN TABLE ft2;
 \d+ fd_pt1
@@ -1472,6 +1476,7 @@ DROP FOREIGN TABLE ft2;
  c3     | date    |           |          |         | plain    |              | 
 Not-null constraints:
     "fd_pt1_c1_not_null" NOT NULL "c1"
+Parallel DML: unsafe
 
 CREATE FOREIGN TABLE ft2 (
 	c1 integer NOT NULL,
@@ -1489,6 +1494,7 @@ Not-null constraints:
     "ft2_c1_not_null" NOT NULL "c1"
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
+Parallel DML: unsafe
 
 ALTER FOREIGN TABLE ft2 INHERIT fd_pt1;
 \d+ fd_pt1
@@ -1502,6 +1508,7 @@ Not-null constraints:
     "fd_pt1_c1_not_null" NOT NULL "c1"
 Child tables:
     ft2, FOREIGN
+Parallel DML: unsafe
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1516,6 +1523,7 @@ Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 Inherits:
     fd_pt1
+Parallel DML: unsafe
 
 CREATE TABLE ct3() INHERITS(ft2);
 CREATE FOREIGN TABLE ft3 (
@@ -1543,6 +1551,7 @@ Inherits:
 Child tables:
     ct3
     ft3, FOREIGN
+Parallel DML: unsafe
 
 \d+ ct3
                                     Table "public.ct3"
@@ -1555,6 +1564,7 @@ Not-null constraints:
     "ft2_c1_not_null" NOT NULL "c1" (inherited)
 Inherits:
     ft2
+Parallel DML: unsafe
 
 \d+ ft3
                                        Foreign table "public.ft3"
@@ -1568,6 +1578,7 @@ Not-null constraints:
 Server: s0
 Inherits:
     ft2
+Parallel DML: unsafe
 
 -- add attributes recursively
 ALTER TABLE fd_pt1 ADD COLUMN c4 integer;
@@ -1592,6 +1603,7 @@ Not-null constraints:
     "fd_pt1_c7_not_null" NOT NULL "c7"
 Child tables:
     ft2, FOREIGN
+Parallel DML: unsafe
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1615,6 +1627,7 @@ Inherits:
 Child tables:
     ct3
     ft3, FOREIGN
+Parallel DML: unsafe
 
 \d+ ct3
                                     Table "public.ct3"
@@ -1633,6 +1646,7 @@ Not-null constraints:
     "fd_pt1_c7_not_null" NOT NULL "c7" (inherited)
 Inherits:
     ft2
+Parallel DML: unsafe
 
 \d+ ft3
                                        Foreign table "public.ft3"
@@ -1652,6 +1666,7 @@ Not-null constraints:
 Server: s0
 Inherits:
     ft2
+Parallel DML: unsafe
 
 -- alter attributes recursively
 ALTER TABLE fd_pt1 ALTER COLUMN c4 SET DEFAULT 0;
@@ -1683,6 +1698,7 @@ Not-null constraints:
     "fd_pt1_c6_not_null" NOT NULL "c6"
 Child tables:
     ft2, FOREIGN
+Parallel DML: unsafe
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1706,6 +1722,7 @@ Inherits:
 Child tables:
     ct3
     ft3, FOREIGN
+Parallel DML: unsafe
 
 -- drop attributes recursively
 ALTER TABLE fd_pt1 DROP COLUMN c4;
@@ -1724,6 +1741,7 @@ Not-null constraints:
     "fd_pt1_c1_not_null" NOT NULL "c1"
 Child tables:
     ft2, FOREIGN
+Parallel DML: unsafe
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1741,6 +1759,7 @@ Inherits:
 Child tables:
     ct3
     ft3, FOREIGN
+Parallel DML: unsafe
 
 -- add constraints recursively
 ALTER TABLE fd_pt1 ADD CONSTRAINT fd_pt1chk1 CHECK (c1 > 0) NO INHERIT;
@@ -1772,6 +1791,7 @@ Not-null constraints:
     "fd_pt1_c1_not_null" NOT NULL "c1"
 Child tables:
     ft2, FOREIGN
+Parallel DML: unsafe
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1791,6 +1811,7 @@ Inherits:
 Child tables:
     ct3
     ft3, FOREIGN
+Parallel DML: unsafe
 
 DROP FOREIGN TABLE ft2; -- ERROR
 ERROR:  cannot drop foreign table ft2 because other objects depend on it
@@ -1826,6 +1847,7 @@ Not-null constraints:
     "fd_pt1_c1_not_null" NOT NULL "c1"
 Child tables:
     ft2, FOREIGN
+Parallel DML: unsafe
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1842,6 +1864,7 @@ Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 Inherits:
     fd_pt1
+Parallel DML: unsafe
 
 -- drop constraints recursively
 ALTER TABLE fd_pt1 DROP CONSTRAINT fd_pt1chk1 CASCADE;
@@ -1862,6 +1885,7 @@ Not-null constraints:
     "fd_pt1_c1_not_null" NOT NULL "c1"
 Child tables:
     ft2, FOREIGN
+Parallel DML: unsafe
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1879,6 +1903,7 @@ Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 Inherits:
     fd_pt1
+Parallel DML: unsafe
 
 -- VALIDATE CONSTRAINT need do nothing on foreign tables
 ALTER TABLE fd_pt1 VALIDATE CONSTRAINT fd_pt1chk3;
@@ -1895,6 +1920,7 @@ Not-null constraints:
     "fd_pt1_c1_not_null" NOT NULL "c1"
 Child tables:
     ft2, FOREIGN
+Parallel DML: unsafe
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1912,6 +1938,7 @@ Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 Inherits:
     fd_pt1
+Parallel DML: unsafe
 
 -- changes name of an attribute recursively
 ALTER TABLE fd_pt1 RENAME COLUMN c1 TO f1;
@@ -1932,6 +1959,7 @@ Not-null constraints:
     "fd_pt1_c1_not_null" NOT NULL "f1"
 Child tables:
     ft2, FOREIGN
+Parallel DML: unsafe
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1949,6 +1977,7 @@ Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 Inherits:
     fd_pt1
+Parallel DML: unsafe
 
 DROP TABLE fd_pt1 CASCADE;
 NOTICE:  drop cascades to foreign table ft2
@@ -1996,6 +2025,7 @@ Not-null constraints:
     "fd_pt2_c1_not_null" NOT NULL "c1"
 Partitions:
     fd_pt2_1 FOR VALUES IN (1), FOREIGN
+Parallel DML: unsafe
 
 \d+ fd_pt2_1
                                      Foreign table "public.fd_pt2_1"
@@ -2010,6 +2040,7 @@ Not-null constraints:
     "fd_pt2_c1_not_null" NOT NULL "c1" (inherited)
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
+Parallel DML: unsafe
 
 -- partition cannot have additional columns
 DROP FOREIGN TABLE fd_pt2_1;
@@ -2031,6 +2062,7 @@ Not-null constraints:
     "fd_pt2_1_c1_not_null" NOT NULL "c1"
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
+Parallel DML: unsafe
 
 ALTER TABLE fd_pt2 ATTACH PARTITION fd_pt2_1 FOR VALUES IN (1);       -- ERROR
 ERROR:  table "fd_pt2_1" contains column "c4" not found in parent "fd_pt2"
@@ -2047,6 +2079,7 @@ Partition key: LIST (c1)
 Not-null constraints:
     "fd_pt2_c1_not_null" NOT NULL "c1"
 Number of partitions: 0
+Parallel DML: unsafe
 
 CREATE FOREIGN TABLE fd_pt2_1 (
 	c1 integer NOT NULL,
@@ -2064,6 +2097,7 @@ Not-null constraints:
     "fd_pt2_1_c1_not_null" NOT NULL "c1"
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
+Parallel DML: unsafe
 
 -- no attach partition validation occurs for foreign tables
 ALTER TABLE fd_pt2 ATTACH PARTITION fd_pt2_1 FOR VALUES IN (1);
@@ -2079,6 +2113,7 @@ Not-null constraints:
     "fd_pt2_c1_not_null" NOT NULL "c1"
 Partitions:
     fd_pt2_1 FOR VALUES IN (1), FOREIGN
+Parallel DML: unsafe
 
 \d+ fd_pt2_1
                                      Foreign table "public.fd_pt2_1"
@@ -2093,6 +2128,7 @@ Not-null constraints:
     "fd_pt2_1_c1_not_null" NOT NULL "c1" (inherited)
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
+Parallel DML: unsafe
 
 -- cannot add column to a partition
 ALTER TABLE fd_pt2_1 ADD c4 char;
@@ -2112,6 +2148,7 @@ Not-null constraints:
     "fd_pt2_c1_not_null" NOT NULL "c1"
 Partitions:
     fd_pt2_1 FOR VALUES IN (1), FOREIGN
+Parallel DML: unsafe
 
 \d+ fd_pt2_1
                                      Foreign table "public.fd_pt2_1"
@@ -2129,6 +2166,7 @@ Not-null constraints:
     "fd_pt2_1_c3_not_null" NOT NULL "c3"
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
+Parallel DML: unsafe
 
 -- cannot drop inherited NOT NULL constraint from a partition
 ALTER TABLE fd_pt2_1 ALTER c1 DROP NOT NULL;
@@ -2148,6 +2186,7 @@ Not-null constraints:
     "fd_pt2_c1_not_null" NOT NULL "c1"
     "fd_pt2_c2_not_null" NOT NULL "c2"
 Number of partitions: 0
+Parallel DML: unsafe
 
 \d+ fd_pt2_1
                                      Foreign table "public.fd_pt2_1"
@@ -2163,6 +2202,7 @@ Not-null constraints:
     "fd_pt2_1_c3_not_null" NOT NULL "c3"
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
+Parallel DML: unsafe
 
 ALTER TABLE fd_pt2 ATTACH PARTITION fd_pt2_1 FOR VALUES IN (1);       -- ERROR
 ERROR:  column "c2" in child table "fd_pt2_1" must be marked NOT NULL
@@ -2184,6 +2224,7 @@ Not-null constraints:
     "fd_pt2_c1_not_null" NOT NULL "c1"
     "fd_pt2_c2_not_null" NOT NULL "c2"
 Number of partitions: 0
+Parallel DML: unsafe
 
 \d+ fd_pt2_1
                                      Foreign table "public.fd_pt2_1"
@@ -2200,6 +2241,7 @@ Not-null constraints:
     "fd_pt2_1_c3_not_null" NOT NULL "c3"
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
+Parallel DML: unsafe
 
 ALTER TABLE fd_pt2 ATTACH PARTITION fd_pt2_1 FOR VALUES IN (1);       -- ERROR
 ERROR:  child table is missing constraint "fd_pt2chk1"
diff --git a/src/test/regress/expected/generated_stored.out b/src/test/regress/expected/generated_stored.out
index 7866ae0ebbe..35089d7b9fe 100644
--- a/src/test/regress/expected/generated_stored.out
+++ b/src/test/regress/expected/generated_stored.out
@@ -376,6 +376,7 @@ Not-null constraints:
     "gtest1_a_not_null" NOT NULL "a" (inherited)
 Inherits:
     gtest1
+Parallel DML: unsafe
 
 INSERT INTO gtestx (a, x) VALUES (11, 22);
 SELECT * FROM gtest1;
diff --git a/src/test/regress/expected/generated_virtual.out b/src/test/regress/expected/generated_virtual.out
index 24d5dbf46ca..d670c3787a6 100644
--- a/src/test/regress/expected/generated_virtual.out
+++ b/src/test/regress/expected/generated_virtual.out
@@ -370,6 +370,7 @@ Not-null constraints:
     "gtest1_a_not_null" NOT NULL "a" (inherited)
 Inherits:
     gtest1
+Parallel DML: unsafe
 
 INSERT INTO gtestx (a, x) VALUES (11, 22);
 SELECT * FROM gtest1;
diff --git a/src/test/regress/expected/identity.out b/src/test/regress/expected/identity.out
index 0398a19484f..612d11a9c8f 100644
--- a/src/test/regress/expected/identity.out
+++ b/src/test/regress/expected/identity.out
@@ -584,6 +584,7 @@ Not-null constraints:
     "itest8_f2_not_null" NOT NULL "f2"
     "itest8_f3_not_null" NOT NULL "f3"
     "itest8_f4_not_null" NOT NULL "f4"
+Parallel DML: unsafe
 
 \d itest8_f2_seq
                    Sequence "public.itest8_f2_seq"
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 3d8e8d8afd2..2937bd228e7 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1099,6 +1099,7 @@ ALTER TABLE inhts RENAME d TO dd;
 Inherits:
     inht1
     inhs1
+Parallel DML: unsafe
 
 DROP TABLE inhts;
 -- Test for adding a column to a parent table with complex inheritance
@@ -1120,6 +1121,7 @@ NOTICE:  merging definition of column "j" for child "inhtd"
 Child tables:
     inhtb
     inhtd
+Parallel DML: unsafe
 
 \d+ inhtd
                                    Table "public.inhtd"
@@ -1131,6 +1133,7 @@ Inherits:
     inhta
     inhtb
     inhtc
+Parallel DML: unsafe
 
 DROP TABLE inhta, inhtb, inhtc, inhtd;
 -- Test for renaming in diamond inheritance
@@ -1152,6 +1155,7 @@ ALTER TABLE inht1 RENAME aa TO aaa;
 Inherits:
     inht2
     inht3
+Parallel DML: unsafe
 
 CREATE TABLE inhts (d int) INHERITS (inht2, inhs1);
 NOTICE:  merging multiple inherited definitions of column "b"
@@ -1170,6 +1174,7 @@ ERROR:  cannot rename inherited column "b"
 Inherits:
     inht2
     inhs1
+Parallel DML: unsafe
 
 WITH RECURSIVE r AS (
   SELECT 'inht1'::regclass AS inhrelid
@@ -1217,6 +1222,7 @@ Indexes:
     "test_constraints_val1_val2_key" UNIQUE CONSTRAINT, btree (val1, val2)
 Child tables:
     test_constraints_inh
+Parallel DML: unsafe
 
 ALTER TABLE ONLY test_constraints DROP CONSTRAINT test_constraints_val1_val2_key;
 \d+ test_constraints
@@ -1228,6 +1234,7 @@ ALTER TABLE ONLY test_constraints DROP CONSTRAINT test_constraints_val1_val2_key
  val2   | integer           |           |          |         | plain    |              | 
 Child tables:
     test_constraints_inh
+Parallel DML: unsafe
 
 \d+ test_constraints_inh
                                  Table "public.test_constraints_inh"
@@ -1238,6 +1245,7 @@ Child tables:
  val2   | integer           |           |          |         | plain    |              | 
 Inherits:
     test_constraints
+Parallel DML: unsafe
 
 DROP TABLE test_constraints_inh;
 DROP TABLE test_constraints;
@@ -1255,6 +1263,7 @@ Indexes:
     "test_ex_constraints_c_excl" EXCLUDE USING gist (c WITH &&)
 Child tables:
     test_ex_constraints_inh
+Parallel DML: unsafe
 
 ALTER TABLE test_ex_constraints DROP CONSTRAINT test_ex_constraints_c_excl;
 \d+ test_ex_constraints
@@ -1264,6 +1273,7 @@ ALTER TABLE test_ex_constraints DROP CONSTRAINT test_ex_constraints_c_excl;
  c      | circle |           |          |         | plain   |              | 
 Child tables:
     test_ex_constraints_inh
+Parallel DML: unsafe
 
 \d+ test_ex_constraints_inh
                          Table "public.test_ex_constraints_inh"
@@ -1272,6 +1282,7 @@ Child tables:
  c      | circle |           |          |         | plain   |              | 
 Inherits:
     test_ex_constraints
+Parallel DML: unsafe
 
 DROP TABLE test_ex_constraints_inh;
 DROP TABLE test_ex_constraints;
@@ -1290,6 +1301,7 @@ Referenced by:
     TABLE "test_foreign_constraints" CONSTRAINT "test_foreign_constraints_id1_fkey" FOREIGN KEY (id1) REFERENCES test_primary_constraints(id)
 Not-null constraints:
     "test_primary_constraints_id_not_null" NOT NULL "id"
+Parallel DML: unsafe
 
 \d+ test_foreign_constraints
                          Table "public.test_foreign_constraints"
@@ -1300,6 +1312,7 @@ Foreign-key constraints:
     "test_foreign_constraints_id1_fkey" FOREIGN KEY (id1) REFERENCES test_primary_constraints(id)
 Child tables:
     test_foreign_constraints_inh
+Parallel DML: unsafe
 
 ALTER TABLE test_foreign_constraints DROP CONSTRAINT test_foreign_constraints_id1_fkey;
 \d+ test_foreign_constraints
@@ -1309,6 +1322,7 @@ ALTER TABLE test_foreign_constraints DROP CONSTRAINT test_foreign_constraints_id
  id1    | integer |           |          |         | plain   |              | 
 Child tables:
     test_foreign_constraints_inh
+Parallel DML: unsafe
 
 \d+ test_foreign_constraints_inh
                        Table "public.test_foreign_constraints_inh"
@@ -1317,6 +1331,7 @@ Child tables:
  id1    | integer |           |          |         | plain   |              | 
 Inherits:
     test_foreign_constraints
+Parallel DML: unsafe
 
 DROP TABLE test_foreign_constraints_inh;
 DROP TABLE test_foreign_constraints;
@@ -2287,6 +2302,7 @@ Inherits:
     pp1
     cc1
     cc2
+Parallel DML: unsafe
 
 alter table cc3 no inherit pp1;
 alter table cc3 no inherit cc1;
@@ -2301,6 +2317,7 @@ alter table cc3 no inherit cc2;
  f4     | double precision |           |          |         | plain    |              | 
 Not-null constraints:
     "pp1_f1_not_null" NOT NULL "f1"
+Parallel DML: unsafe
 
 drop table cc3;
 -- named NOT NULL constraint
@@ -2320,6 +2337,7 @@ Inherits:
     pp1
 Child tables:
     cc2
+Parallel DML: unsafe
 
 \d+ cc2
                                          Table "public.cc2"
@@ -2336,6 +2354,7 @@ Not-null constraints:
 Inherits:
     pp1
     cc1
+Parallel DML: unsafe
 
 alter table pp1 alter column f1 set not null;
 \d+ pp1
@@ -2348,6 +2367,7 @@ Not-null constraints:
 Child tables:
     cc1
     cc2
+Parallel DML: unsafe
 
 \d+ cc1
                                     Table "public.cc1"
@@ -2364,6 +2384,7 @@ Inherits:
     pp1
 Child tables:
     cc2
+Parallel DML: unsafe
 
 \d+ cc2
                                          Table "public.cc2"
@@ -2380,6 +2401,7 @@ Not-null constraints:
 Inherits:
     pp1
     cc1
+Parallel DML: unsafe
 
 -- cannot create table with inconsistent NO INHERIT constraint
 create table cc3 (a2 int not null no inherit) inherits (cc1);
@@ -2410,6 +2432,7 @@ Inherits:
     pp1
 Child tables:
     cc2
+Parallel DML: unsafe
 
 -- same for cc2
 alter table cc2 alter column f1 drop not null;
@@ -2428,6 +2451,7 @@ Not-null constraints:
 Inherits:
     pp1
     cc1
+Parallel DML: unsafe
 
 -- remove from cc1, should fail again
 alter table cc1 alter column f1 drop not null;
@@ -2442,6 +2466,7 @@ alter table pp1 alter column f1 drop not null;
 Child tables:
     cc1
     cc2
+Parallel DML: unsafe
 
 alter table pp1 add primary key (f1);
 -- Leave these tables around, for pg_upgrade testing
@@ -2458,6 +2483,7 @@ alter table inh_child no inherit inh_parent;
  f2     | integer |           |          |         | plain   |              | 
 Not-null constraints:
     "inh_child_f1_not_null" NOT NULL "f1" NO INHERIT
+Parallel DML: unsafe
 
 drop table inh_parent, inh_child;
 -- test that inhcount is updated correctly through multiple inheritance
@@ -2478,6 +2504,7 @@ alter table inh_cc2 no inherit inh_cc1;
  f4     | double precision |           |          |         | plain    |              | 
 Not-null constraints:
     "inh_pp1_f1_not_null" NOT NULL "f1"
+Parallel DML: unsafe
 
 drop table inh_pp1, inh_cc1, inh_cc2;
 create table inh_pp1 (f1 int not null);
@@ -2496,6 +2523,7 @@ alter table inh_pp1 alter column f1 drop not null;
 Inherits:
     inh_pp1
     inh_cc1
+Parallel DML: unsafe
 
 drop table inh_pp1, inh_cc1, inh_cc2;
 -- Test a not-null addition that must walk down the hierarchy
@@ -2522,6 +2550,7 @@ Not-null constraints:
 Inherits:
     inh_parent1
     inh_parent2
+Parallel DML: unsafe
 
 create table inh_child2 (constraint foo not null a) inherits (inh_parent1, inh_parent2);
 alter table inh_child2 no inherit inh_parent2;
@@ -2536,6 +2565,7 @@ Not-null constraints:
     "nn" NOT NULL "b"
 Inherits:
     inh_parent1
+Parallel DML: unsafe
 
 drop table inh_parent1, inh_parent2, inh_child1, inh_child2;
 -- Test multiple parents with overlapping primary keys
@@ -2577,6 +2607,7 @@ Not-null constraints:
 Inherits:
     inh_parent1
     inh_parent2
+Parallel DML: unsafe
 
 drop table inh_parent1, inh_parent2, inh_child;
 -- NOT NULL NO INHERIT
@@ -2602,6 +2633,7 @@ select conrelid::regclass, conname, contype, conkey,
  a      | integer |           |          |         | plain   |              | 
 Inherits:
     inh_nn_parent
+Parallel DML: unsafe
 
                                Table "public.inh_nn_child2"
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
@@ -2609,6 +2641,7 @@ Inherits:
  a      | integer |           |          |         | plain   |              | 
 Inherits:
     inh_nn_parent
+Parallel DML: unsafe
 
                                Table "public.inh_nn_parent"
  Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
@@ -2619,6 +2652,7 @@ Not-null constraints:
 Child tables:
     inh_nn_child
     inh_nn_child2
+Parallel DML: unsafe
 
 drop table inh_nn_parent, inh_nn_child, inh_nn_child2;
 CREATE TABLE inh_nn_parent (a int, NOT NULL a NO INHERIT);
@@ -2679,6 +2713,7 @@ Not-null constraints:
     "inh_parent_f1_not_null" NOT NULL "f1"
 Child tables:
     inh_child1
+Parallel DML: unsafe
 
 \d+ inh_child1
                                 Table "public.inh_child1"
@@ -2691,6 +2726,7 @@ Inherits:
     inh_parent
 Child tables:
     inh_child2
+Parallel DML: unsafe
 
 \d+ inh_child2
                                 Table "public.inh_child2"
@@ -2701,6 +2737,7 @@ Not-null constraints:
     "inh_child2_f1_not_null" NOT NULL "f1" (local, inherited)
 Inherits:
     inh_child1
+Parallel DML: unsafe
 
 select conrelid::regclass, conname, contype, coninhcount, conislocal
  from pg_constraint where contype = 'n' and
@@ -2726,6 +2763,7 @@ alter table inh_child1 no inherit inh_parent;
  f1     | integer |           | not null |         | plain   |              | 
 Not-null constraints:
     "inh_parent_f1_not_null" NOT NULL "f1"
+Parallel DML: unsafe
 
 \d+ inh_child1
                                 Table "public.inh_child1"
@@ -2737,6 +2775,7 @@ Not-null constraints:
 Child tables:
     inh_child2
     inh_child3
+Parallel DML: unsafe
 
 \d+ inh_child2
                                 Table "public.inh_child2"
@@ -2747,6 +2786,7 @@ Not-null constraints:
     "inh_child2_f1_not_null" NOT NULL "f1" (local, inherited)
 Inherits:
     inh_child1
+Parallel DML: unsafe
 
 select conrelid::regclass, conname, contype, coninhcount, conislocal
  from pg_constraint where contype = 'n' and
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
index 75b8de79fce..e971b62ae2d 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -177,6 +177,7 @@ Rules:
     irule3 AS
     ON INSERT TO inserttest2 DO  INSERT INTO inserttest (f4[1].if1, f4[1].if2[2])  SELECT new.f1,
             new.f2
+Parallel DML: unsafe
 
 drop table inserttest2;
 drop table inserttest;
@@ -270,6 +271,7 @@ Rules:
     irule3 AS
     ON INSERT TO inserttest2 DO  INSERT INTO inserttestb (f4[1].if1, f4[1].if2[2])  SELECT new.f1,
             new.f2
+Parallel DML: unsafe
 
 drop table inserttest2;
 drop table inserttesta;
@@ -575,6 +577,7 @@ Partitions:
     part_null FOR VALUES IN (NULL)
     part_xx_yy FOR VALUES IN ('xx', 'yy'), PARTITIONED
     part_default DEFAULT, PARTITIONED
+Parallel DML: unsafe
 
 -- cleanup
 drop table range_parted, list_parted;
@@ -590,6 +593,7 @@ create table part_default partition of list_parted default;
  a      | integer |           |          |         | plain   |              | 
 Partition of: list_parted DEFAULT
 No partition constraint
+Parallel DML: unsafe
 
 insert into part_default values (null);
 insert into part_default values (1);
@@ -982,6 +986,7 @@ Partitions:
     mcrparted6_common_ge_10 FOR VALUES FROM ('common', 10) TO ('common', MAXVALUE)
     mcrparted7_gt_common_lt_d FOR VALUES FROM ('common', MAXVALUE) TO ('d', MINVALUE)
     mcrparted8_ge_d FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, MAXVALUE)
+Parallel DML: unsafe
 
 \d+ mcrparted1_lt_b
                               Table "public.mcrparted1_lt_b"
@@ -991,6 +996,7 @@ Partitions:
  b      | integer |           |          |         | plain    |              | 
 Partition of: mcrparted FOR VALUES FROM (MINVALUE, MINVALUE) TO ('b', MINVALUE)
 Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a < 'b'::text))
+Parallel DML: unsafe
 
 \d+ mcrparted2_b
                                 Table "public.mcrparted2_b"
@@ -1000,6 +1006,7 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a < 'b'::text))
  b      | integer |           |          |         | plain    |              | 
 Partition of: mcrparted FOR VALUES FROM ('b', MINVALUE) TO ('c', MINVALUE)
 Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'b'::text) AND (a < 'c'::text))
+Parallel DML: unsafe
 
 \d+ mcrparted3_c_to_common
                            Table "public.mcrparted3_c_to_common"
@@ -1009,6 +1016,7 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'b'::text)
  b      | integer |           |          |         | plain    |              | 
 Partition of: mcrparted FOR VALUES FROM ('c', MINVALUE) TO ('common', MINVALUE)
 Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'c'::text) AND (a < 'common'::text))
+Parallel DML: unsafe
 
 \d+ mcrparted4_common_lt_0
                            Table "public.mcrparted4_common_lt_0"
@@ -1018,6 +1026,7 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'c'::text)
  b      | integer |           |          |         | plain    |              | 
 Partition of: mcrparted FOR VALUES FROM ('common', MINVALUE) TO ('common', 0)
 Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::text) AND (b < 0))
+Parallel DML: unsafe
 
 \d+ mcrparted5_common_0_to_10
                          Table "public.mcrparted5_common_0_to_10"
@@ -1027,6 +1036,7 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::te
  b      | integer |           |          |         | plain    |              | 
 Partition of: mcrparted FOR VALUES FROM ('common', 0) TO ('common', 10)
 Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::text) AND (b >= 0) AND (b < 10))
+Parallel DML: unsafe
 
 \d+ mcrparted6_common_ge_10
                           Table "public.mcrparted6_common_ge_10"
@@ -1036,6 +1046,7 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::te
  b      | integer |           |          |         | plain    |              | 
 Partition of: mcrparted FOR VALUES FROM ('common', 10) TO ('common', MAXVALUE)
 Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::text) AND (b >= 10))
+Parallel DML: unsafe
 
 \d+ mcrparted7_gt_common_lt_d
                          Table "public.mcrparted7_gt_common_lt_d"
@@ -1045,6 +1056,7 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::te
  b      | integer |           |          |         | plain    |              | 
 Partition of: mcrparted FOR VALUES FROM ('common', MAXVALUE) TO ('d', MINVALUE)
 Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a > 'common'::text) AND (a < 'd'::text))
+Parallel DML: unsafe
 
 \d+ mcrparted8_ge_d
                               Table "public.mcrparted8_ge_d"
@@ -1054,6 +1066,7 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a > 'common'::te
  b      | integer |           |          |         | plain    |              | 
 Partition of: mcrparted FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, MAXVALUE)
 Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'd'::text))
+Parallel DML: unsafe
 
 insert into mcrparted values ('aaa', 0), ('b', 0), ('bz', 10), ('c', -10),
     ('comm', -10), ('common', -10), ('common', 0), ('common', 10),
diff --git a/src/test/regress/expected/partition_merge.out b/src/test/regress/expected/partition_merge.out
index d3818f1bf9b..057f8e466d4 100644
--- a/src/test/regress/expected/partition_merge.out
+++ b/src/test/regress/expected/partition_merge.out
@@ -661,6 +661,7 @@ Indexes:
     "tp_1_2_i_idx" btree (i)
 Not-null constraints:
     "t_i_not_null" NOT NULL "i" (inherited)
+Parallel DML: unsafe
 
 DROP TABLE t;
 --
@@ -941,6 +942,7 @@ Not-null constraints:
 Triggers:
     t_before_insert_row_trigger BEFORE INSERT ON tp_0_1 FOR EACH ROW EXECUTE FUNCTION trigger_function('t'), ON TABLE t
     tp_0_1_before_insert_row_trigger BEFORE INSERT ON tp_0_1 FOR EACH ROW EXECUTE FUNCTION trigger_function('tp_0_1')
+Parallel DML: unsafe
 
 ALTER TABLE t MERGE PARTITIONS (tp_0_1, tp_1_2) INTO tp_0_1;
 \d+ tp_0_1
@@ -962,6 +964,7 @@ Not-null constraints:
     "t_b_nn" NOT NULL "b" (inherited) NOT VALID
 Triggers:
     t_before_insert_row_trigger BEFORE INSERT ON tp_0_1 FOR EACH ROW EXECUTE FUNCTION trigger_function('t'), ON TABLE t
+Parallel DML: unsafe
 
 INSERT INTO t(i, t, b) VALUES(1, DEFAULT, 3);
 NOTICE:  trigger(t) called: action = INSERT, when = BEFORE, level = ROW
diff --git a/src/test/regress/expected/partition_split.out b/src/test/regress/expected/partition_split.out
index 961b37953c8..7c9c82a3a24 100644
--- a/src/test/regress/expected/partition_split.out
+++ b/src/test/regress/expected/partition_split.out
@@ -139,6 +139,7 @@ Partitions:
     partition_split_schema2.sales_feb2022 FOR VALUES FROM ('02-01-2022') TO ('03-01-2022')
     partition_split_schema2.sales_mar2022 FOR VALUES FROM ('03-01-2022') TO ('04-01-2022')
     sales_jan2022 FOR VALUES FROM ('01-01-2022') TO ('02-01-2022')
+Parallel DML: unsafe
 
 DROP TABLE sales_range;
 DROP TABLE sales_others;
@@ -244,6 +245,7 @@ Partitions:
     sales_feb2022 FOR VALUES FROM ('02-01-2022') TO ('03-01-2022')
     sales_jan2022 FOR VALUES FROM ('01-01-2022') TO ('02-01-2022')
     sales_others DEFAULT
+Parallel DML: unsafe
 
 SELECT tableoid::regclass, * FROM sales_range ORDER BY tableoid::regclass::text COLLATE "C", salesperson_id;
                tableoid                | salesperson_id | salesperson_name | sales_amount | sales_date 
@@ -1312,6 +1314,7 @@ CREATE TABLE t_bigint_default PARTITION OF t_bigint DEFAULT;
 Partition key: RANGE (b)
 Partitions:
     t_bigint_default DEFAULT
+Parallel DML: unsafe
 
 \d+ t_bigint_default
                                     Table "partition_split_schema.t_bigint_default"
@@ -1323,6 +1326,7 @@ Partitions:
  k      | integer |           |          | generated always as ((b + 10)) stored | plain   |              | 
 Partition of: t_bigint DEFAULT
 No partition constraint
+Parallel DML: unsafe
 
 ALTER TABLE t_bigint SPLIT PARTITION t_bigint_default INTO
   (PARTITION t_bigint_01_10 FOR VALUES FROM (0) TO (10),
@@ -1338,6 +1342,7 @@ ALTER TABLE t_bigint SPLIT PARTITION t_bigint_default INTO
  k      | integer |           |          | generated always as ((b + 10)) stored | plain   |              | 
 Partition of: t_bigint DEFAULT
 Partition constraint: (NOT ((b IS NOT NULL) AND ((b >= '0'::bigint) AND (b < '10'::bigint))))
+Parallel DML: unsafe
 
 \d+ t_bigint_01_10
                                      Table "partition_split_schema.t_bigint_01_10"
@@ -1349,6 +1354,7 @@ Partition constraint: (NOT ((b IS NOT NULL) AND ((b >= '0'::bigint) AND (b < '10
  k      | integer |           |          | generated always as ((b + 10)) stored | plain   |              | 
 Partition of: t_bigint FOR VALUES FROM ('0') TO ('10')
 Partition constraint: ((b IS NOT NULL) AND (b >= '0'::bigint) AND (b < '10'::bigint))
+Parallel DML: unsafe
 
 DROP TABLE t_bigint;
 -- Test permission checks.  The user needs to own the parent table and the
@@ -1517,6 +1523,7 @@ Not-null constraints:
 Triggers:
     t_before_insert_row_trigger BEFORE INSERT ON tp_x FOR EACH ROW EXECUTE FUNCTION trigger_function('t'), ON TABLE t
     tp_x_before_insert_row_trigger BEFORE INSERT ON tp_x FOR EACH ROW EXECUTE FUNCTION trigger_function('tp_x')
+Parallel DML: unsafe
 
 ALTER TABLE t SPLIT PARTITION tp_x INTO
   (PARTITION tp_0_1 FOR VALUES FROM (0) TO (1),
@@ -1540,6 +1547,7 @@ Not-null constraints:
     "t_b_nn" NOT NULL "b" (inherited) NOT VALID
 Triggers:
     t_before_insert_row_trigger BEFORE INSERT ON tp_x FOR EACH ROW EXECUTE FUNCTION trigger_function('t'), ON TABLE t
+Parallel DML: unsafe
 
 INSERT INTO t(i, t, b) VALUES(1, DEFAULT, 3);
 NOTICE:  trigger(t) called: action = INSERT, when = BEFORE, level = ROW
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index c8f3932edf0..dc349c05b4c 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -3022,6 +3022,7 @@ CREATE MATERIALIZED VIEW mat_view_heap_psql USING heap_psql AS SELECT f1 from tb
 --------+----------------+-----------+----------+---------+----------+--------------+-------------
  f1     | integer        |           |          |         | plain    |              | 
  f2     | character(100) |           |          |         | extended |              | 
+Parallel DML: unsafe
 
 \d+ tbl_heap
                                  Table "tableam_display.tbl_heap"
@@ -3029,6 +3030,7 @@ CREATE MATERIALIZED VIEW mat_view_heap_psql USING heap_psql AS SELECT f1 from tb
 --------+----------------+-----------+----------+---------+----------+--------------+-------------
  f1     | integer        |           |          |         | plain    |              | 
  f2     | character(100) |           |          |         | extended |              | 
+Parallel DML: unsafe
 
 \set HIDE_TABLEAM off
 \d+ tbl_heap_psql
@@ -3038,6 +3040,7 @@ CREATE MATERIALIZED VIEW mat_view_heap_psql USING heap_psql AS SELECT f1 from tb
  f1     | integer        |           |          |         | plain    |              | 
  f2     | character(100) |           |          |         | extended |              | 
 Access method: heap_psql
+Parallel DML: unsafe
 
 \d+ tbl_heap
                                  Table "tableam_display.tbl_heap"
@@ -3046,50 +3049,51 @@ Access method: heap_psql
  f1     | integer        |           |          |         | plain    |              | 
  f2     | character(100) |           |          |         | extended |              | 
 Access method: heap
+Parallel DML: unsafe
 
 -- AM is displayed for tables, indexes and materialized views.
 \d+
-                                                           List of relations
-     Schema      |        Name        |       Type        |        Owner         | Persistence | Access method |  Size   | Description 
------------------+--------------------+-------------------+----------------------+-------------+---------------+---------+-------------
- tableam_display | mat_view_heap_psql | materialized view | regress_display_role | permanent   | heap_psql     | 0 bytes | 
- tableam_display | tbl_heap           | table             | regress_display_role | permanent   | heap          | 0 bytes | 
- tableam_display | tbl_heap_psql      | table             | regress_display_role | permanent   | heap_psql     | 0 bytes | 
- tableam_display | view_heap_psql     | view              | regress_display_role | permanent   |               | 0 bytes | 
+                                                                  List of relations
+     Schema      |        Name        |       Type        |        Owner         | Persistence | Access method | Parallel DML |  Size   | Description 
+-----------------+--------------------+-------------------+----------------------+-------------+---------------+--------------+---------+-------------
+ tableam_display | mat_view_heap_psql | materialized view | regress_display_role | permanent   | heap_psql     | unsafe       | 0 bytes | 
+ tableam_display | tbl_heap           | table             | regress_display_role | permanent   | heap          | unsafe       | 0 bytes | 
+ tableam_display | tbl_heap_psql      | table             | regress_display_role | permanent   | heap_psql     | unsafe       | 0 bytes | 
+ tableam_display | view_heap_psql     | view              | regress_display_role | permanent   |               | unsafe       | 0 bytes | 
 (4 rows)
 
 \dt+
-                                                    List of tables
-     Schema      |     Name      | Type  |        Owner         | Persistence | Access method |  Size   | Description 
------------------+---------------+-------+----------------------+-------------+---------------+---------+-------------
- tableam_display | tbl_heap      | table | regress_display_role | permanent   | heap          | 0 bytes | 
- tableam_display | tbl_heap_psql | table | regress_display_role | permanent   | heap_psql     | 0 bytes | 
+                                                           List of tables
+     Schema      |     Name      | Type  |        Owner         | Persistence | Access method | Parallel DML |  Size   | Description 
+-----------------+---------------+-------+----------------------+-------------+---------------+--------------+---------+-------------
+ tableam_display | tbl_heap      | table | regress_display_role | permanent   | heap          | unsafe       | 0 bytes | 
+ tableam_display | tbl_heap_psql | table | regress_display_role | permanent   | heap_psql     | unsafe       | 0 bytes | 
 (2 rows)
 
 \dm+
-                                                      List of materialized views
-     Schema      |        Name        |       Type        |        Owner         | Persistence | Access method |  Size   | Description 
------------------+--------------------+-------------------+----------------------+-------------+---------------+---------+-------------
- tableam_display | mat_view_heap_psql | materialized view | regress_display_role | permanent   | heap_psql     | 0 bytes | 
+                                                              List of materialized views
+     Schema      |        Name        |       Type        |        Owner         | Persistence | Access method | Parallel DML |  Size   | Description 
+-----------------+--------------------+-------------------+----------------------+-------------+---------------+--------------+---------+-------------
+ tableam_display | mat_view_heap_psql | materialized view | regress_display_role | permanent   | heap_psql     | unsafe       | 0 bytes | 
 (1 row)
 
 -- But not for views and sequences.
 \dv+
-                                            List of views
-     Schema      |      Name      | Type |        Owner         | Persistence |  Size   | Description 
------------------+----------------+------+----------------------+-------------+---------+-------------
- tableam_display | view_heap_psql | view | regress_display_role | permanent   | 0 bytes | 
+                                                    List of views
+     Schema      |      Name      | Type |        Owner         | Persistence | Parallel DML |  Size   | Description 
+-----------------+----------------+------+----------------------+-------------+--------------+---------+-------------
+ tableam_display | view_heap_psql | view | regress_display_role | permanent   | unsafe       | 0 bytes | 
 (1 row)
 
 \set HIDE_TABLEAM on
 \d+
-                                                   List of relations
-     Schema      |        Name        |       Type        |        Owner         | Persistence |  Size   | Description 
------------------+--------------------+-------------------+----------------------+-------------+---------+-------------
- tableam_display | mat_view_heap_psql | materialized view | regress_display_role | permanent   | 0 bytes | 
- tableam_display | tbl_heap           | table             | regress_display_role | permanent   | 0 bytes | 
- tableam_display | tbl_heap_psql      | table             | regress_display_role | permanent   | 0 bytes | 
- tableam_display | view_heap_psql     | view              | regress_display_role | permanent   | 0 bytes | 
+                                                          List of relations
+     Schema      |        Name        |       Type        |        Owner         | Persistence | Parallel DML |  Size   | Description 
+-----------------+--------------------+-------------------+----------------------+-------------+--------------+---------+-------------
+ tableam_display | mat_view_heap_psql | materialized view | regress_display_role | permanent   | unsafe       | 0 bytes | 
+ tableam_display | tbl_heap           | table             | regress_display_role | permanent   | unsafe       | 0 bytes | 
+ tableam_display | tbl_heap_psql      | table             | regress_display_role | permanent   | unsafe       | 0 bytes | 
+ tableam_display | view_heap_psql     | view              | regress_display_role | permanent   | unsafe       | 0 bytes | 
 (4 rows)
 
 -- \d with 'x' enables expanded mode, but only without a pattern
@@ -3099,41 +3103,46 @@ Access method: heap
 --------+----------------+-----------+----------+---------+----------+--------------+-------------
  f1     | integer        |           |          |         | plain    |              | 
  f2     | character(100) |           |          |         | extended |              | 
+Parallel DML: unsafe
 
 \d+x
 List of relations
--[ RECORD 1 ]---------------------
-Schema      | tableam_display
-Name        | mat_view_heap_psql
-Type        | materialized view
-Owner       | regress_display_role
-Persistence | permanent
-Size        | 0 bytes
-Description | 
--[ RECORD 2 ]---------------------
-Schema      | tableam_display
-Name        | tbl_heap
-Type        | table
-Owner       | regress_display_role
-Persistence | permanent
-Size        | 0 bytes
-Description | 
--[ RECORD 3 ]---------------------
-Schema      | tableam_display
-Name        | tbl_heap_psql
-Type        | table
-Owner       | regress_display_role
-Persistence | permanent
-Size        | 0 bytes
-Description | 
--[ RECORD 4 ]---------------------
-Schema      | tableam_display
-Name        | view_heap_psql
-Type        | view
-Owner       | regress_display_role
-Persistence | permanent
-Size        | 0 bytes
-Description | 
+-[ RECORD 1 ]+---------------------
+Schema       | tableam_display
+Name         | mat_view_heap_psql
+Type         | materialized view
+Owner        | regress_display_role
+Persistence  | permanent
+Parallel DML | unsafe
+Size         | 0 bytes
+Description  | 
+-[ RECORD 2 ]+---------------------
+Schema       | tableam_display
+Name         | tbl_heap
+Type         | table
+Owner        | regress_display_role
+Persistence  | permanent
+Parallel DML | unsafe
+Size         | 0 bytes
+Description  | 
+-[ RECORD 3 ]+---------------------
+Schema       | tableam_display
+Name         | tbl_heap_psql
+Type         | table
+Owner        | regress_display_role
+Persistence  | permanent
+Parallel DML | unsafe
+Size         | 0 bytes
+Description  | 
+-[ RECORD 4 ]+---------------------
+Schema       | tableam_display
+Name         | view_heap_psql
+Type         | view
+Owner        | regress_display_role
+Persistence  | permanent
+Parallel DML | unsafe
+Size         | 0 bytes
+Description  | 
 
 RESET ROLE;
 RESET search_path;
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 29e54b214a0..13e1e180481 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -214,6 +214,7 @@ Included in publications:
     "testpub_foralltables"
 Not-null constraints:
     "testpub_tbl2_id_not_null" NOT NULL "id"
+Parallel DML: unsafe
 
 \dRp+ testpub_foralltables
                                                        Publication testpub_foralltables
@@ -1166,6 +1167,7 @@ Included in publications:
     "testpub_fortable" (a, b)
 Not-null constraints:
     "testpub_tbl7_a_not_null" NOT NULL "a"
+Parallel DML: unsafe
 
 -- ok: the column list is the same, we should skip this table (or at least not fail)
 ALTER PUBLICATION testpub_fortable SET TABLE testpub_tbl7 (a, b);
@@ -1182,6 +1184,7 @@ Included in publications:
     "testpub_fortable" (a, b)
 Not-null constraints:
     "testpub_tbl7_a_not_null" NOT NULL "a"
+Parallel DML: unsafe
 
 -- ok: the column list changes, make sure the catalog gets updated
 ALTER PUBLICATION testpub_fortable SET TABLE testpub_tbl7 (a, c);
@@ -1198,6 +1201,7 @@ Included in publications:
     "testpub_fortable" (a, c)
 Not-null constraints:
     "testpub_tbl7_a_not_null" NOT NULL "a"
+Parallel DML: unsafe
 
 -- column list for partitioned tables has to cover replica identities for
 -- all child relations
@@ -1337,6 +1341,7 @@ Included in publications:
 Not-null constraints:
     "testpub_tbl_both_filters_a_not_null" NOT NULL "a"
     "testpub_tbl_both_filters_c_not_null" NOT NULL "c"
+Parallel DML: unsafe
 
 DROP TABLE testpub_tbl_both_filters;
 DROP PUBLICATION testpub_both_filters;
@@ -1553,6 +1558,7 @@ Included in publications:
     "testpub_default"
     "testpub_fortbl"
     "testpub_ins_trunct"
+Parallel DML: unsafe
 
 \d+ testpub_tbl1
                                                 Table "public.testpub_tbl1"
@@ -1568,6 +1574,7 @@ Included in publications:
     "testpub_ins_trunct"
 Not-null constraints:
     "testpub_tbl1_id_not_null" NOT NULL "id"
+Parallel DML: unsafe
 
 \dRp+ testpub_default
                                                             Publication testpub_default
@@ -1595,6 +1602,7 @@ Included in publications:
     "testpub_ins_trunct"
 Not-null constraints:
     "testpub_tbl1_id_not_null" NOT NULL "id"
+Parallel DML: unsafe
 
 -- verify relation cache invalidation when a primary key is added using
 -- an existing index
diff --git a/src/test/regress/expected/replica_identity.out b/src/test/regress/expected/replica_identity.out
index 336b04fa278..95fc5c9241e 100644
--- a/src/test/regress/expected/replica_identity.out
+++ b/src/test/regress/expected/replica_identity.out
@@ -179,6 +179,7 @@ Not-null constraints:
     "test_replica_identity_keya_not_null" NOT NULL "keya"
     "test_replica_identity_keyb_not_null" NOT NULL "keyb"
 Replica Identity: FULL
+Parallel DML: unsafe
 
 ALTER TABLE test_replica_identity REPLICA IDENTITY NOTHING;
 SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass;
@@ -264,6 +265,7 @@ Not-null constraints:
     "test_replica_identity4_id_not_null" NOT NULL "id"
 Partitions:
     test_replica_identity4_1 FOR VALUES IN (1)
+Parallel DML: unsafe
 
 ALTER INDEX test_replica_identity4_pkey
   ATTACH PARTITION test_replica_identity4_1_pkey;
@@ -279,6 +281,7 @@ Not-null constraints:
     "test_replica_identity4_id_not_null" NOT NULL "id"
 Partitions:
     test_replica_identity4_1 FOR VALUES IN (1)
+Parallel DML: unsafe
 
 -- Dropping the primary key is not allowed if that would leave the replica
 -- identity as nullable
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 3a5e82c35bd..1cc4b42ea95 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -1265,6 +1265,7 @@ Partitions:
     part_document_fiction FOR VALUES FROM (11) TO (12)
     part_document_nonfiction FOR VALUES FROM (99) TO (100)
     part_document_satire FOR VALUES FROM (55) TO (56)
+Parallel DML: unsafe
 
 SELECT * FROM pg_policies WHERE schemaname = 'regress_rls_schema' AND tablename like '%part_document%' ORDER BY policyname;
      schemaname     |   tablename   | policyname | permissive  |       roles        | cmd |                    qual                    | with_check 
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index a65a5bf0c4f..bf7aad19066 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -3339,6 +3339,7 @@ Rules:
             wdel
   RETURNING trgt.f1,
     trgt.f2
+Parallel DML: unsafe
 
 --
 -- Also check multiassignment deparsing.
@@ -3362,6 +3363,7 @@ Rules:
   WHERE trgt.f1 = new.f1
   RETURNING new.f1,
     new.f2
+Parallel DML: unsafe
 
 drop table rule_t1, rule_dest;
 --
diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out
index 37070c1a896..fcb096640d1 100644
--- a/src/test/regress/expected/stats_ext.out
+++ b/src/test/regress/expected/stats_ext.out
@@ -210,6 +210,7 @@ ALTER STATISTICS ab1_a_b_stats SET STATISTICS -1;
  b      | integer |           |          |         | plain   |              | 
 Statistics objects:
     "public.ab1_a_b_stats" ON a, b FROM ab1
+Parallel DML: unsafe
 
 -- partial analyze doesn't build stats either
 ANALYZE ab1 (a);
diff --git a/src/test/regress/expected/tablespace.out b/src/test/regress/expected/tablespace.out
index f0dd25cdf0c..1544078608a 100644
--- a/src/test/regress/expected/tablespace.out
+++ b/src/test/regress/expected/tablespace.out
@@ -358,6 +358,7 @@ Indexes:
 Partitions:
     testschema.part1 FOR VALUES IN (1)
     testschema.part2 FOR VALUES IN (2)
+Parallel DML: unsafe
 
 \d testschema.part1
              Table "testschema.part1"
@@ -377,6 +378,7 @@ Partition of: testschema.part FOR VALUES IN (1)
 Partition constraint: ((a IS NOT NULL) AND (a = 1))
 Indexes:
     "part1_a_idx" btree (a), tablespace "regress_tblspace"
+Parallel DML: unsafe
 
 \d testschema.part_a_idx
 Partitioned index "testschema.part_a_idx"
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index 8fcb33ac81a..af6bbbd75bd 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -3574,6 +3574,7 @@ Triggers:
     parenttrig AFTER INSERT ON child FOR EACH ROW EXECUTE FUNCTION f()
 Inherits:
     parent
+Parallel DML: unsafe
 
 drop table parent, child;
 drop function f();
diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out
index eef2bac1cbf..61687eb0292 100644
--- a/src/test/regress/expected/update.out
+++ b/src/test/regress/expected/update.out
@@ -759,6 +759,7 @@ create table part_def partition of range_parted default;
  e      | character varying |           |          |         | extended |              | 
 Partition of: range_parted DEFAULT
 Partition constraint: (NOT ((a IS NOT NULL) AND (b IS NOT NULL) AND (((a = 'a'::text) AND (b >= '1'::bigint) AND (b < '10'::bigint)) OR ((a = 'a'::text) AND (b >= '10'::bigint) AND (b < '20'::bigint)) OR ((a = 'b'::text) AND (b >= '1'::bigint) AND (b < '10'::bigint)) OR ((a = 'b'::text) AND (b >= '10'::bigint) AND (b < '20'::bigint)) OR ((a = 'b'::text) AND (b >= '20'::bigint) AND (b < '30'::bigint)))))
+Parallel DML: unsafe
 
 insert into range_parted values ('c', 9);
 -- ok
-- 
2.53.0

