&& !SxactIsReadOnly(farConflict->sxactOut)
&& !SxactIsDoomed(farConflict->sxactOut)))
{
+ /*
+ * Normally, we kill the pivot transaction to make sure we
+ * make progress if the failing transaction is retried.
+ * However, we can't kill it if it's already prepared, so
+ * in that case we commit suicide instead.
+ */
+ if (SxactIsPrepared(nearConflict->sxactOut))
+ {
+ LWLockRelease(SerializableXactHashLock);
+ ereport(ERROR,
+ (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+ errmsg("could not serialize access due to read/write dependencies among transactions"),
+ errdetail("Cancelled on commit attempt with conflict in from prepared pivot."),
+ errhint("The transaction might succeed if retried.")));
+ }
nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
break;
}
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
INSERT INTO pxtest1 VALUES ('fff');
+-- This should fail, because the gid foo3 is already in use
+PREPARE TRANSACTION 'foo3';
+ERROR: transaction identifier "foo3" is already in use
SELECT * FROM pxtest1;
foobar
--------
aaa
ddd
- fff
-(3 rows)
+(2 rows)
--- This should fail, because the gid foo3 is already in use
-PREPARE TRANSACTION 'foo3';
-ERROR: transaction identifier "foo3" is already in use
+ROLLBACK PREPARED 'foo3';
SELECT * FROM pxtest1;
foobar
--------
ddd
(2 rows)
-ROLLBACK PREPARED 'foo3';
+-- Test serialization failure (SSI)
+BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd';
+SELECT * FROM pxtest1;
+ foobar
+--------
+ aaa
+ eee
+(2 rows)
+
+PREPARE TRANSACTION 'foo4';
+SELECT gid FROM pg_prepared_xacts;
+ gid
+------
+ foo4
+(1 row)
+
+BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT * FROM pxtest1;
foobar
--------
ddd
(2 rows)
+INSERT INTO pxtest1 VALUES ('fff');
+-- This should fail, because the two transactions have a write-skew anomaly
+PREPARE TRANSACTION 'foo5';
+ERROR: could not serialize access due to read/write dependencies among transactions
+DETAIL: Cancelled on commit attempt with conflict in from prepared pivot.
+HINT: The transaction might succeed if retried.
+SELECT gid FROM pg_prepared_xacts;
+ gid
+------
+ foo4
+(1 row)
+
+ROLLBACK PREPARED 'foo4';
+SELECT gid FROM pg_prepared_xacts;
+ gid
+-----
+(0 rows)
+
-- Clean up
DROP TABLE pxtest1;
-- Test subtransactions
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
INSERT INTO pxtest1 VALUES ('fff');
-SELECT * FROM pxtest1;
-- This should fail, because the gid foo3 is already in use
PREPARE TRANSACTION 'foo3';
SELECT * FROM pxtest1;
+-- Test serialization failure (SSI)
+BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd';
+SELECT * FROM pxtest1;
+PREPARE TRANSACTION 'foo4';
+
+SELECT gid FROM pg_prepared_xacts;
+
+BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+SELECT * FROM pxtest1;
+INSERT INTO pxtest1 VALUES ('fff');
+
+-- This should fail, because the two transactions have a write-skew anomaly
+PREPARE TRANSACTION 'foo5';
+
+SELECT gid FROM pg_prepared_xacts;
+
+ROLLBACK PREPARED 'foo4';
+
+SELECT gid FROM pg_prepared_xacts;
+
-- Clean up
DROP TABLE pxtest1;