Skip to content

Commit 6011e43

Browse files
author
Commitfest Bot
committed
[PATCH]: ./Inherit-xact-properties-in-postgres-fdw-v2.patch
1 parent 3aad76a commit 6011e43

File tree

6 files changed

+165
-4
lines changed

6 files changed

+165
-4
lines changed

contrib/postgres_fdw/connection.c

+13-4
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,9 @@ do_sql_command_end(PGconn *conn, const char *sql, bool consume_input)
843843
* those scans. A disadvantage is that we can't provide sane emulation of
844844
* READ COMMITTED behavior --- it would be nice if we had some other way to
845845
* control which remote queries share a snapshot.
846+
*
847+
* Note that we always start remote transactions with the same read/write
848+
* and deferrable properties as the local (top-level) transaction.
846849
*/
847850
static void
848851
begin_remote_xact(ConnCacheEntry *entry)
@@ -852,17 +855,23 @@ begin_remote_xact(ConnCacheEntry *entry)
852855
/* Start main transaction if we haven't yet */
853856
if (entry->xact_depth <= 0)
854857
{
855-
const char *sql;
858+
StringInfoData sql;
856859

857860
elog(DEBUG3, "starting remote transaction on connection %p",
858861
entry->conn);
859862

863+
initStringInfo(&sql);
864+
appendStringInfoString(&sql, "START TRANSACTION ISOLATION LEVEL ");
860865
if (IsolationIsSerializable())
861-
sql = "START TRANSACTION ISOLATION LEVEL SERIALIZABLE";
866+
appendStringInfoString(&sql, "SERIALIZABLE");
862867
else
863-
sql = "START TRANSACTION ISOLATION LEVEL REPEATABLE READ";
868+
appendStringInfoString(&sql, "REPEATABLE READ");
869+
if (TopTransactionIsReadOnly())
870+
appendStringInfoString(&sql, " READ ONLY");
871+
if (XactDeferrable)
872+
appendStringInfoString(&sql, " DEFERRABLE");
864873
entry->changing_xact_state = true;
865-
do_sql_command(entry->conn, sql);
874+
do_sql_command(entry->conn, sql.data);
866875
entry->xact_depth = 1;
867876
entry->changing_xact_state = false;
868877
}

contrib/postgres_fdw/expected/postgres_fdw.out

+72
Original file line numberDiff line numberDiff line change
@@ -12309,6 +12309,78 @@ SELECT count(*) FROM remote_application_name
1230912309
DROP FOREIGN TABLE remote_application_name;
1231012310
DROP VIEW my_application_name;
1231112311
-- ===================================================================
12312+
-- test read-only and/or deferrable transactions
12313+
-- ===================================================================
12314+
CREATE TABLE loct (f1 int, f2 text);
12315+
CREATE FUNCTION locf() RETURNS SETOF loct LANGUAGE SQL AS
12316+
'UPDATE public.loct SET f2 = f2 || f2 RETURNING *';
12317+
CREATE VIEW locv AS SELECT t.* FROM locf() t;
12318+
CREATE FOREIGN TABLE remt (f1 int, f2 text)
12319+
SERVER loopback OPTIONS (table_name 'locv');
12320+
INSERT INTO loct VALUES (1, 'foo'), (2, 'bar');
12321+
SELECT * FROM loct;
12322+
f1 | f2
12323+
----+-----
12324+
1 | foo
12325+
2 | bar
12326+
(2 rows)
12327+
12328+
SELECT * FROM remt; -- should work
12329+
f1 | f2
12330+
----+--------
12331+
1 | foofoo
12332+
2 | barbar
12333+
(2 rows)
12334+
12335+
SELECT * FROM loct;
12336+
f1 | f2
12337+
----+--------
12338+
1 | foofoo
12339+
2 | barbar
12340+
(2 rows)
12341+
12342+
START TRANSACTION READ ONLY;
12343+
SELECT * FROM remt; -- should fail
12344+
ERROR: cannot execute UPDATE in a read-only transaction
12345+
CONTEXT: SQL function "locf" statement 1
12346+
remote SQL command: SELECT f1, f2 FROM public.locv
12347+
ROLLBACK;
12348+
DROP FOREIGN TABLE remt;
12349+
CREATE FOREIGN TABLE remt (f1 int, f2 text)
12350+
SERVER loopback OPTIONS (table_name 'loct');
12351+
START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY;
12352+
SELECT * FROM remt;
12353+
f1 | f2
12354+
----+--------
12355+
1 | foofoo
12356+
2 | barbar
12357+
(2 rows)
12358+
12359+
COMMIT;
12360+
START TRANSACTION ISOLATION LEVEL SERIALIZABLE DEFERRABLE;
12361+
SELECT * FROM remt;
12362+
f1 | f2
12363+
----+--------
12364+
1 | foofoo
12365+
2 | barbar
12366+
(2 rows)
12367+
12368+
COMMIT;
12369+
START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE;
12370+
SELECT * FROM remt;
12371+
f1 | f2
12372+
----+--------
12373+
1 | foofoo
12374+
2 | barbar
12375+
(2 rows)
12376+
12377+
COMMIT;
12378+
-- Clean up
12379+
DROP FOREIGN TABLE remt;
12380+
DROP VIEW locv;
12381+
DROP FUNCTION locf();
12382+
DROP TABLE loct;
12383+
-- ===================================================================
1231212384
-- test parallel commit and parallel abort
1231312385
-- ===================================================================
1231412386
ALTER SERVER loopback OPTIONS (ADD parallel_commit 'true');

contrib/postgres_fdw/sql/postgres_fdw.sql

+42
Original file line numberDiff line numberDiff line change
@@ -4187,6 +4187,48 @@ SELECT count(*) FROM remote_application_name
41874187
DROP FOREIGN TABLE remote_application_name;
41884188
DROP VIEW my_application_name;
41894189

4190+
-- ===================================================================
4191+
-- test read-only and/or deferrable transactions
4192+
-- ===================================================================
4193+
CREATE TABLE loct (f1 int, f2 text);
4194+
CREATE FUNCTION locf() RETURNS SETOF loct LANGUAGE SQL AS
4195+
'UPDATE public.loct SET f2 = f2 || f2 RETURNING *';
4196+
CREATE VIEW locv AS SELECT t.* FROM locf() t;
4197+
CREATE FOREIGN TABLE remt (f1 int, f2 text)
4198+
SERVER loopback OPTIONS (table_name 'locv');
4199+
4200+
INSERT INTO loct VALUES (1, 'foo'), (2, 'bar');
4201+
SELECT * FROM loct;
4202+
4203+
SELECT * FROM remt; -- should work
4204+
SELECT * FROM loct;
4205+
4206+
START TRANSACTION READ ONLY;
4207+
SELECT * FROM remt; -- should fail
4208+
ROLLBACK;
4209+
4210+
DROP FOREIGN TABLE remt;
4211+
CREATE FOREIGN TABLE remt (f1 int, f2 text)
4212+
SERVER loopback OPTIONS (table_name 'loct');
4213+
4214+
START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY;
4215+
SELECT * FROM remt;
4216+
COMMIT;
4217+
4218+
START TRANSACTION ISOLATION LEVEL SERIALIZABLE DEFERRABLE;
4219+
SELECT * FROM remt;
4220+
COMMIT;
4221+
4222+
START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE;
4223+
SELECT * FROM remt;
4224+
COMMIT;
4225+
4226+
-- Clean up
4227+
DROP FOREIGN TABLE remt;
4228+
DROP VIEW locv;
4229+
DROP FUNCTION locf();
4230+
DROP TABLE loct;
4231+
41904232
-- ===================================================================
41914233
-- test parallel commit and parallel abort
41924234
-- ===================================================================

doc/src/sgml/postgres-fdw.sgml

+16
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,22 @@ postgres=# SELECT postgres_fdw_disconnect_all();
10771077
<productname>PostgreSQL</productname> release might modify these rules.
10781078
</para>
10791079

1080+
<para>
1081+
The remote transaction is opened in the same read/write mode as the local
1082+
transaction: if the local transaction has been declared
1083+
<literal>READ ONLY</literal> at the top level, the remote transaction is
1084+
opened in <literal>READ ONLY</literal> mode, otherwise it is opened in
1085+
<literal>READ WRITE</literal> mode.
1086+
</para>
1087+
1088+
<para>
1089+
The remote transaction is also opened in the same deferrable mode as the
1090+
local transaction: if the local transaction has been declared
1091+
<literal>DEFERRABLE</literal> at the top level, the remote transaction is
1092+
opened in <literal>DEFERRABLE</literal> mode, otherwise it is opened in
1093+
<literal>NOT DEFERRABLE</literal> mode.
1094+
</para>
1095+
10801096
<para>
10811097
Note that it is currently not supported by
10821098
<filename>postgres_fdw</filename> to prepare the remote transaction for

src/backend/access/transam/xact.c

+21
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,27 @@ TransactionStartedDuringRecovery(void)
10441044
return CurrentTransactionState->startedInRecovery;
10451045
}
10461046

1047+
/*
1048+
* TopTransactionIsReadOnly
1049+
*
1050+
* Returns true if the transaction has been declared READ ONLY at the top
1051+
* level.
1052+
*/
1053+
bool
1054+
TopTransactionIsReadOnly(void)
1055+
{
1056+
TransactionState s = CurrentTransactionState;
1057+
1058+
if (s->nestingLevel == 1)
1059+
return XactReadOnly;
1060+
while (s->nestingLevel > 2)
1061+
{
1062+
Assert(s->parent != NULL);
1063+
s = s->parent;
1064+
}
1065+
return s->prevXactReadOnly;
1066+
}
1067+
10471068
/*
10481069
* EnterParallelMode
10491070
*/

src/include/access/xact.h

+1
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ extern TimestampTz GetCurrentTransactionStopTimestamp(void);
458458
extern void SetCurrentStatementStartTimestamp(void);
459459
extern int GetCurrentTransactionNestLevel(void);
460460
extern bool TransactionIdIsCurrentTransactionId(TransactionId xid);
461+
extern bool TopTransactionIsReadOnly(void);
461462
extern void CommandCounterIncrement(void);
462463
extern void ForceSyncCommit(void);
463464
extern void StartTransactionCommand(void);

0 commit comments

Comments
 (0)