From a63756e4c4097db223186fb575f74a35318ebf41 Mon Sep 17 00:00:00 2001
From: houzj <houzj.fnst@cn.fujitsu.com>
Date: Thu, 11 Mar 2021 18:31:27 +0800
Subject: [PATCH] avoid cci

---
 src/backend/executor/spi.c          | 27 +++++++++++----------
 src/backend/utils/adt/ri_triggers.c | 47 ++++++++++++++++++++++++++-----------
 src/include/executor/spi.h          |  3 ++-
 3 files changed, 50 insertions(+), 27 deletions(-)

diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 00aa78e..3b84d8c 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -69,7 +69,8 @@ static int	_SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
 							  bool read_only, bool no_snapshots,
 							  bool fire_triggers, uint64 tcount,
 							  DestReceiver *caller_dest,
-							  ResourceOwner plan_owner);
+							  ResourceOwner plan_owner,
+							  bool needCCI);
 
 static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes,
 										 Datum *Values, const char *Nulls);
@@ -525,7 +526,7 @@ SPI_execute(const char *src, bool read_only, long tcount)
 							InvalidSnapshot, InvalidSnapshot,
 							read_only, false,
 							true, tcount,
-							NULL, NULL);
+							NULL, NULL, true);
 
 	_SPI_end_call(true);
 	return res;
@@ -569,7 +570,7 @@ SPI_execute_extended(const char *src,
 							InvalidSnapshot, InvalidSnapshot,
 							options->read_only, options->no_snapshots,
 							true, options->tcount,
-							options->dest, options->owner);
+							options->dest, options->owner, true);
 
 	_SPI_end_call(true);
 	return res;
@@ -598,7 +599,7 @@ SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
 							InvalidSnapshot, InvalidSnapshot,
 							read_only, false,
 							true, tcount,
-							NULL, NULL);
+							NULL, NULL, true);
 
 	_SPI_end_call(true);
 	return res;
@@ -629,7 +630,7 @@ SPI_execute_plan_extended(SPIPlanPtr plan,
 							InvalidSnapshot, InvalidSnapshot,
 							options->read_only, options->no_snapshots,
 							true, options->tcount,
-							options->dest, options->owner);
+							options->dest, options->owner, true);
 
 	_SPI_end_call(true);
 	return res;
@@ -653,7 +654,7 @@ SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params,
 							InvalidSnapshot, InvalidSnapshot,
 							read_only, false,
 							true, tcount,
-							NULL, NULL);
+							NULL, NULL, true);
 
 	_SPI_end_call(true);
 	return res;
@@ -676,7 +677,8 @@ int
 SPI_execute_snapshot(SPIPlanPtr plan,
 					 Datum *Values, const char *Nulls,
 					 Snapshot snapshot, Snapshot crosscheck_snapshot,
-					 bool read_only, bool fire_triggers, long tcount)
+					 bool read_only, bool fire_triggers, long tcount,
+					 bool needCCI)
 {
 	int			res;
 
@@ -696,7 +698,7 @@ SPI_execute_snapshot(SPIPlanPtr plan,
 							snapshot, crosscheck_snapshot,
 							read_only, false,
 							fire_triggers, tcount,
-							NULL, NULL);
+							NULL, NULL, needCCI);
 
 	_SPI_end_call(true);
 	return res;
@@ -746,7 +748,7 @@ SPI_execute_with_args(const char *src,
 							InvalidSnapshot, InvalidSnapshot,
 							read_only, false,
 							true, tcount,
-							NULL, NULL);
+							NULL, NULL, true);
 
 	_SPI_end_call(true);
 	return res;
@@ -2277,7 +2279,8 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
 				  Snapshot snapshot, Snapshot crosscheck_snapshot,
 				  bool read_only, bool no_snapshots,
 				  bool fire_triggers, uint64 tcount,
-				  DestReceiver *caller_dest, ResourceOwner plan_owner)
+				  DestReceiver *caller_dest, ResourceOwner plan_owner,
+				  bool needCCI)
 {
 	int			my_res = 0;
 	uint64		my_processed = 0;
@@ -2464,7 +2467,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
 			 * If not read-only mode, advance the command counter before each
 			 * command and update the snapshot.
 			 */
-			if (!read_only && !no_snapshots)
+			if (needCCI && !read_only && !no_snapshots)
 			{
 				CommandCounterIncrement();
 				UpdateActiveSnapshotCommandId();
@@ -2608,7 +2611,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
 		 * command.  This ensures that its effects are visible, in case it was
 		 * DDL that would affect the next CachedPlanSource.
 		 */
-		if (!read_only)
+		if (needCCI && !read_only)
 			CommandCounterIncrement();
 	}
 
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 6e3a410..468fb4f 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -213,7 +213,7 @@ static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo,
 							RI_QueryKey *qkey, SPIPlanPtr qplan,
 							Relation fk_rel, Relation pk_rel,
 							TupleTableSlot *oldslot, TupleTableSlot *newslot,
-							bool detectNewRows, int expect_OK);
+							bool detectNewRows, int expect_OK, bool modifypk);
 static void ri_ExtractValues(Relation rel, TupleTableSlot *slot,
 							 const RI_ConstraintInfo *riinfo, bool rel_is_pk,
 							 Datum *vals, char *nulls);
@@ -229,7 +229,7 @@ static void ri_ReportViolation(const RI_ConstraintInfo *riinfo,
  * Check foreign key existence (combined for INSERT and UPDATE).
  */
 static Datum
-RI_FKey_check(TriggerData *trigdata)
+RI_FKey_check(TriggerData *trigdata, bool modifypk)
 {
 	const RI_ConstraintInfo *riinfo;
 	Relation	fk_rel;
@@ -393,7 +393,8 @@ RI_FKey_check(TriggerData *trigdata)
 					fk_rel, pk_rel,
 					NULL, newslot,
 					false,
-					SPI_OK_SELECT);
+					SPI_OK_SELECT,
+					modifypk);
 
 	if (SPI_finish() != SPI_OK_FINISH)
 		elog(ERROR, "SPI_finish failed");
@@ -412,11 +413,24 @@ RI_FKey_check(TriggerData *trigdata)
 Datum
 RI_FKey_check_ins(PG_FUNCTION_ARGS)
 {
+	bool modifypk = true;
+
 	/* Check that this is a valid trigger call on the right time and event. */
 	ri_CheckTrigger(fcinfo, "RI_FKey_check_ins", RI_TRIGTYPE_INSERT);
 
+	/*
+	 * In parallel mode, any other modifications other
+	 * than the insert event itself are parallel unsafe.
+	 * So, there is no chance to modify the pk relation.
+	 * 
+	 * Once we support extra modifications in parallel mode,
+	 * this dependency is no longer needed.
+	 */
+	if (IsInParallelMode())
+		modifypk = false;
+
 	/* Share code with UPDATE case. */
-	return RI_FKey_check((TriggerData *) fcinfo->context);
+	return RI_FKey_check((TriggerData *) fcinfo->context, modifypk);
 }
 
 
@@ -432,7 +446,7 @@ RI_FKey_check_upd(PG_FUNCTION_ARGS)
 	ri_CheckTrigger(fcinfo, "RI_FKey_check_upd", RI_TRIGTYPE_UPDATE);
 
 	/* Share code with INSERT case. */
-	return RI_FKey_check((TriggerData *) fcinfo->context);
+	return RI_FKey_check((TriggerData *) fcinfo->context, true);
 }
 
 
@@ -520,7 +534,8 @@ ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
 							 fk_rel, pk_rel,
 							 oldslot, NULL,
 							 true,	/* treat like update */
-							 SPI_OK_SELECT);
+							 SPI_OK_SELECT,
+							 true);
 
 	if (SPI_finish() != SPI_OK_FINISH)
 		elog(ERROR, "SPI_finish failed");
@@ -712,7 +727,8 @@ ri_restrict(TriggerData *trigdata, bool is_no_action)
 					fk_rel, pk_rel,
 					oldslot, NULL,
 					true,		/* must detect new rows */
-					SPI_OK_SELECT);
+					SPI_OK_SELECT,
+					true);
 
 	if (SPI_finish() != SPI_OK_FINISH)
 		elog(ERROR, "SPI_finish failed");
@@ -818,7 +834,8 @@ RI_FKey_cascade_del(PG_FUNCTION_ARGS)
 					fk_rel, pk_rel,
 					oldslot, NULL,
 					true,		/* must detect new rows */
-					SPI_OK_DELETE);
+					SPI_OK_DELETE,
+					true);
 
 	if (SPI_finish() != SPI_OK_FINISH)
 		elog(ERROR, "SPI_finish failed");
@@ -939,7 +956,8 @@ RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
 					fk_rel, pk_rel,
 					oldslot, newslot,
 					true,		/* must detect new rows */
-					SPI_OK_UPDATE);
+					SPI_OK_UPDATE,
+					true);
 
 	if (SPI_finish() != SPI_OK_FINISH)
 		elog(ERROR, "SPI_finish failed");
@@ -1118,7 +1136,8 @@ ri_set(TriggerData *trigdata, bool is_set_null)
 					fk_rel, pk_rel,
 					oldslot, NULL,
 					true,		/* must detect new rows */
-					SPI_OK_UPDATE);
+					SPI_OK_UPDATE,
+					true);
 
 	if (SPI_finish() != SPI_OK_FINISH)
 		elog(ERROR, "SPI_finish failed");
@@ -1492,7 +1511,7 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
 									  NULL, NULL,
 									  GetLatestSnapshot(),
 									  InvalidSnapshot,
-									  true, false, 1);
+									  true, false, 1, true);
 
 	/* Check result */
 	if (spi_result != SPI_OK_SELECT)
@@ -1732,7 +1751,7 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
 									  NULL, NULL,
 									  GetLatestSnapshot(),
 									  InvalidSnapshot,
-									  true, false, 1);
+									  true, false, 1, true);
 
 	/* Check result */
 	if (spi_result != SPI_OK_SELECT)
@@ -2179,7 +2198,7 @@ ri_PerformCheck(const RI_ConstraintInfo *riinfo,
 				RI_QueryKey *qkey, SPIPlanPtr qplan,
 				Relation fk_rel, Relation pk_rel,
 				TupleTableSlot *oldslot, TupleTableSlot *newslot,
-				bool detectNewRows, int expect_OK)
+				bool detectNewRows, int expect_OK, bool modifypk)
 {
 	Relation	query_rel,
 				source_rel;
@@ -2277,7 +2296,7 @@ ri_PerformCheck(const RI_ConstraintInfo *riinfo,
 	spi_result = SPI_execute_snapshot(qplan,
 									  vals, nulls,
 									  test_snapshot, crosscheck_snapshot,
-									  false, false, limit);
+									  false, false, limit, modifypk);
 
 	/* Restore UID and security context */
 	SetUserIdAndSecContext(save_userid, save_sec_context);
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 6455d10..3dc6b86 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -129,7 +129,8 @@ extern int	SPI_execute_snapshot(SPIPlanPtr plan,
 								 Datum *Values, const char *Nulls,
 								 Snapshot snapshot,
 								 Snapshot crosscheck_snapshot,
-								 bool read_only, bool fire_triggers, long tcount);
+								 bool read_only, bool fire_triggers, long tcount,
+								 bool needCCI);
 extern int	SPI_execute_with_args(const char *src,
 								  int nargs, Oid *argtypes,
 								  Datum *Values, const char *Nulls,
-- 
2.7.2.windows.1

