mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
Advance transaction timestamp for intra-procedure transactions.
Per discussion, this behavior seems less astonishing than not doing so. Peter Eisentraut and Tom Lane Discussion: https://postgr.es/m/20180920234040.GC29981@momjian.us
This commit is contained in:
parent
6eb3eb577d
commit
82ff0cc91d
@ -1887,20 +1887,26 @@ StartTransaction(void)
|
|||||||
TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);
|
TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set transaction_timestamp() (a/k/a now()). We want this to be the same
|
* set transaction_timestamp() (a/k/a now()). Normally, we want this to
|
||||||
* as the first command's statement_timestamp(), so don't do a fresh
|
* be the same as the first command's statement_timestamp(), so don't do a
|
||||||
* GetCurrentTimestamp() call (which'd be expensive anyway). In a
|
* fresh GetCurrentTimestamp() call (which'd be expensive anyway). But
|
||||||
* parallel worker, this should already have been provided by a call to
|
* for transactions started inside procedures (i.e., nonatomic SPI
|
||||||
|
* contexts), we do need to advance the timestamp. Also, in a parallel
|
||||||
|
* worker, the timestamp should already have been provided by a call to
|
||||||
* SetParallelStartTimestamps().
|
* SetParallelStartTimestamps().
|
||||||
*
|
|
||||||
* Also, mark xactStopTimestamp as unset.
|
|
||||||
*/
|
*/
|
||||||
if (!IsParallelWorker())
|
if (!IsParallelWorker())
|
||||||
xactStartTimestamp = stmtStartTimestamp;
|
{
|
||||||
|
if (!SPI_inside_nonatomic_context())
|
||||||
|
xactStartTimestamp = stmtStartTimestamp;
|
||||||
|
else
|
||||||
|
xactStartTimestamp = GetCurrentTimestamp();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Assert(xactStartTimestamp != 0);
|
Assert(xactStartTimestamp != 0);
|
||||||
xactStopTimestamp = 0;
|
|
||||||
pgstat_report_xact_timestamp(xactStartTimestamp);
|
pgstat_report_xact_timestamp(xactStartTimestamp);
|
||||||
|
/* Mark xactStopTimestamp as unset. */
|
||||||
|
xactStopTimestamp = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize current transaction state fields
|
* initialize current transaction state fields
|
||||||
|
@ -423,6 +423,19 @@ AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Are we executing inside a procedure (that is, a nonatomic SPI context)?
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
SPI_inside_nonatomic_context(void)
|
||||||
|
{
|
||||||
|
if (_SPI_current == NULL)
|
||||||
|
return false; /* not in any SPI context at all */
|
||||||
|
if (_SPI_current->atomic)
|
||||||
|
return false; /* it's atomic (ie function not procedure) */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Parse, plan, and execute a query string */
|
/* Parse, plan, and execute a query string */
|
||||||
int
|
int
|
||||||
|
@ -166,5 +166,6 @@ extern void SPI_rollback(void);
|
|||||||
extern void SPICleanup(void);
|
extern void SPICleanup(void);
|
||||||
extern void AtEOXact_SPI(bool isCommit);
|
extern void AtEOXact_SPI(bool isCommit);
|
||||||
extern void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid);
|
extern void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid);
|
||||||
|
extern bool SPI_inside_nonatomic_context(void);
|
||||||
|
|
||||||
#endif /* SPI_H */
|
#endif /* SPI_H */
|
||||||
|
@ -493,6 +493,36 @@ CALL transaction_test10b(10);
|
|||||||
9
|
9
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- transaction timestamp vs. statement timestamp
|
||||||
|
CREATE PROCEDURE transaction_test11()
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
s1 timestamp with time zone;
|
||||||
|
s2 timestamp with time zone;
|
||||||
|
s3 timestamp with time zone;
|
||||||
|
t1 timestamp with time zone;
|
||||||
|
t2 timestamp with time zone;
|
||||||
|
t3 timestamp with time zone;
|
||||||
|
BEGIN
|
||||||
|
s1 := statement_timestamp();
|
||||||
|
t1 := transaction_timestamp();
|
||||||
|
ASSERT s1 = t1;
|
||||||
|
PERFORM pg_sleep(0.001);
|
||||||
|
COMMIT;
|
||||||
|
s2 := statement_timestamp();
|
||||||
|
t2 := transaction_timestamp();
|
||||||
|
ASSERT s2 = s1;
|
||||||
|
ASSERT t2 > t1;
|
||||||
|
PERFORM pg_sleep(0.001);
|
||||||
|
ROLLBACK;
|
||||||
|
s3 := statement_timestamp();
|
||||||
|
t3 := transaction_timestamp();
|
||||||
|
ASSERT s3 = s1;
|
||||||
|
ASSERT t3 > t2;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
CALL transaction_test11();
|
||||||
DROP TABLE test1;
|
DROP TABLE test1;
|
||||||
DROP TABLE test2;
|
DROP TABLE test2;
|
||||||
DROP TABLE test3;
|
DROP TABLE test3;
|
||||||
|
@ -412,6 +412,39 @@ $$;
|
|||||||
CALL transaction_test10b(10);
|
CALL transaction_test10b(10);
|
||||||
|
|
||||||
|
|
||||||
|
-- transaction timestamp vs. statement timestamp
|
||||||
|
CREATE PROCEDURE transaction_test11()
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
s1 timestamp with time zone;
|
||||||
|
s2 timestamp with time zone;
|
||||||
|
s3 timestamp with time zone;
|
||||||
|
t1 timestamp with time zone;
|
||||||
|
t2 timestamp with time zone;
|
||||||
|
t3 timestamp with time zone;
|
||||||
|
BEGIN
|
||||||
|
s1 := statement_timestamp();
|
||||||
|
t1 := transaction_timestamp();
|
||||||
|
ASSERT s1 = t1;
|
||||||
|
PERFORM pg_sleep(0.001);
|
||||||
|
COMMIT;
|
||||||
|
s2 := statement_timestamp();
|
||||||
|
t2 := transaction_timestamp();
|
||||||
|
ASSERT s2 = s1;
|
||||||
|
ASSERT t2 > t1;
|
||||||
|
PERFORM pg_sleep(0.001);
|
||||||
|
ROLLBACK;
|
||||||
|
s3 := statement_timestamp();
|
||||||
|
t3 := transaction_timestamp();
|
||||||
|
ASSERT s3 = s1;
|
||||||
|
ASSERT t3 > t2;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CALL transaction_test11();
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE test1;
|
DROP TABLE test1;
|
||||||
DROP TABLE test2;
|
DROP TABLE test2;
|
||||||
DROP TABLE test3;
|
DROP TABLE test3;
|
||||||
|
Loading…
Reference in New Issue
Block a user