mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +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);
|
||||
|
||||
/*
|
||||
* set transaction_timestamp() (a/k/a now()). We want this to be the same
|
||||
* as the first command's statement_timestamp(), so don't do a fresh
|
||||
* GetCurrentTimestamp() call (which'd be expensive anyway). In a
|
||||
* parallel worker, this should already have been provided by a call to
|
||||
* set transaction_timestamp() (a/k/a now()). Normally, we want this to
|
||||
* be the same as the first command's statement_timestamp(), so don't do a
|
||||
* fresh GetCurrentTimestamp() call (which'd be expensive anyway). But
|
||||
* 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().
|
||||
*
|
||||
* Also, mark xactStopTimestamp as unset.
|
||||
*/
|
||||
if (!IsParallelWorker())
|
||||
xactStartTimestamp = stmtStartTimestamp;
|
||||
{
|
||||
if (!SPI_inside_nonatomic_context())
|
||||
xactStartTimestamp = stmtStartTimestamp;
|
||||
else
|
||||
xactStartTimestamp = GetCurrentTimestamp();
|
||||
}
|
||||
else
|
||||
Assert(xactStartTimestamp != 0);
|
||||
xactStopTimestamp = 0;
|
||||
pgstat_report_xact_timestamp(xactStartTimestamp);
|
||||
/* Mark xactStopTimestamp as unset. */
|
||||
xactStopTimestamp = 0;
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
int
|
||||
|
@ -166,5 +166,6 @@ extern void SPI_rollback(void);
|
||||
extern void SPICleanup(void);
|
||||
extern void AtEOXact_SPI(bool isCommit);
|
||||
extern void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid);
|
||||
extern bool SPI_inside_nonatomic_context(void);
|
||||
|
||||
#endif /* SPI_H */
|
||||
|
@ -493,6 +493,36 @@ CALL transaction_test10b(10);
|
||||
9
|
||||
(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 test2;
|
||||
DROP TABLE test3;
|
||||
|
@ -412,6 +412,39 @@ $$;
|
||||
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 test2;
|
||||
DROP TABLE test3;
|
||||
|
Loading…
Reference in New Issue
Block a user