aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execMain.c12
-rw-r--r--src/backend/executor/execMerge.c3
-rw-r--r--src/backend/executor/execReplication.c22
-rw-r--r--src/backend/executor/nodeLockRows.c5
-rw-r--r--src/backend/executor/nodeModifyTable.c27
5 files changed, 58 insertions, 11 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index cc47f5df402..13ad92745e0 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2733,6 +2733,10 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));
+ if (ItemPointerIndicatesMovedPartitions(&hufd.ctid))
+ ereport(ERROR,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ errmsg("tuple to be locked was already moved to another partition due to concurrent update")));
/* Should not encounter speculative tuple on recheck */
Assert(!HeapTupleHeaderIsSpeculative(tuple.t_data));
@@ -2801,6 +2805,14 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
* As above, it should be safe to examine xmax and t_ctid without the
* buffer content lock, because they can't be changing.
*/
+
+ /* check whether next version would be in a different partition */
+ if (HeapTupleHeaderIndicatesMovedPartitions(tuple.t_data))
+ ereport(ERROR,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ errmsg("tuple to be locked was already moved to another partition due to concurrent update")));
+
+ /* check whether tuple has been deleted */
if (ItemPointerEquals(&tuple.t_self, &tuple.t_data->t_ctid))
{
/* deleted, so forget about it */
diff --git a/src/backend/executor/execMerge.c b/src/backend/executor/execMerge.c
index d39ddd30345..d75d7e5ab26 100644
--- a/src/backend/executor/execMerge.c
+++ b/src/backend/executor/execMerge.c
@@ -324,7 +324,8 @@ lmerge_matched:;
slot = ExecDelete(mtstate, tupleid, NULL,
slot, epqstate, estate,
&tuple_deleted, false, &hufd, action,
- mtstate->canSetTag);
+ mtstate->canSetTag,
+ false /* changingPart */);
break;
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index 6c5a5401c32..b66346702dc 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -191,9 +191,14 @@ retry:
break;
case HeapTupleUpdated:
/* XXX: Improve handling here */
- ereport(LOG,
- (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
- errmsg("concurrent update, retrying")));
+ if (ItemPointerIndicatesMovedPartitions(&hufd.ctid))
+ ereport(LOG,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ errmsg("tuple to be locked was already moved to another partition due to concurrent update, retrying")));
+ else
+ ereport(LOG,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ errmsg("concurrent update, retrying")));
goto retry;
case HeapTupleInvisible:
elog(ERROR, "attempted to lock invisible tuple");
@@ -349,9 +354,14 @@ retry:
break;
case HeapTupleUpdated:
/* XXX: Improve handling here */
- ereport(LOG,
- (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
- errmsg("concurrent update, retrying")));
+ if (ItemPointerIndicatesMovedPartitions(&hufd.ctid))
+ ereport(LOG,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ errmsg("tuple to be locked was already moved to another partition due to concurrent update, retrying")));
+ else
+ ereport(LOG,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ errmsg("concurrent update, retrying")));
goto retry;
case HeapTupleInvisible:
elog(ERROR, "attempted to lock invisible tuple");
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index b39ccf7dc13..ace126cbf24 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -218,6 +218,11 @@ lnext:
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));
+ if (ItemPointerIndicatesMovedPartitions(&hufd.ctid))
+ ereport(ERROR,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ errmsg("tuple to be locked was already moved to another partition due to concurrent update")));
+
if (ItemPointerEquals(&hufd.ctid, &tuple.t_self))
{
/* Tuple was deleted, so don't return it */
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index bf4c2bf6082..f47649d0517 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -645,7 +645,8 @@ ExecDelete(ModifyTableState *mtstate,
bool processReturning,
HeapUpdateFailureData *hufdp,
MergeActionState *actionState,
- bool canSetTag)
+ bool canSetTag,
+ bool changingPart)
{
ResultRelInfo *resultRelInfo;
Relation resultRelationDesc;
@@ -744,7 +745,8 @@ ldelete:;
estate->es_output_cid,
estate->es_crosscheck_snapshot,
true /* wait for commit */ ,
- &hufd);
+ &hufd,
+ changingPart);
/*
* Copy the necessary information, if the caller has asked for it. We
@@ -803,6 +805,10 @@ ldelete:;
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));
+ if (ItemPointerIndicatesMovedPartitions(&hufd.ctid))
+ ereport(ERROR,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ errmsg("tuple to be deleted was already moved to another partition due to concurrent update")));
if (!ItemPointerEquals(tupleid, &hufd.ctid))
{
@@ -1157,7 +1163,7 @@ lreplace:;
*/
ExecDelete(mtstate, tupleid, oldtuple, planSlot, epqstate,
estate, &tuple_deleted, false, hufdp, NULL,
- false);
+ false /* canSetTag */, true /* changingPart */);
/*
* For some reason if DELETE didn't happen (e.g. trigger prevented
@@ -1333,6 +1339,10 @@ lreplace:;
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));
+ if (ItemPointerIndicatesMovedPartitions(&hufd.ctid))
+ ereport(ERROR,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ errmsg("tuple to be updated was already moved to another partition due to concurrent update")));
if (!ItemPointerEquals(tupleid, &hufd.ctid))
{
@@ -1523,6 +1533,14 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
errmsg("could not serialize access due to concurrent update")));
/*
+ * As long as we don't support an UPDATE of INSERT ON CONFLICT for
+ * a partitioned table we shouldn't reach to a case where tuple to
+ * be lock is moved to another partition due to concurrent update
+ * of the partition key.
+ */
+ Assert(!ItemPointerIndicatesMovedPartitions(&hufd.ctid));
+
+ /*
* Tell caller to try again from the very start.
*
* It does not make sense to use the usual EvalPlanQual() style
@@ -2274,7 +2292,8 @@ ExecModifyTable(PlanState *pstate)
case CMD_DELETE:
slot = ExecDelete(node, tupleid, oldtuple, planSlot,
&node->mt_epqstate, estate,
- NULL, true, NULL, NULL, node->canSetTag);
+ NULL, true, NULL, NULL, node->canSetTag,
+ false /* changingPart */);
break;
default:
elog(ERROR, "unknown operation");