diff options
-rw-r--r-- | contrib/postgres_fdw/connection.c | 99 | ||||
-rw-r--r-- | contrib/postgres_fdw/expected/postgres_fdw.out | 134 | ||||
-rw-r--r-- | contrib/postgres_fdw/sql/postgres_fdw.sql | 78 | ||||
-rw-r--r-- | doc/src/sgml/postgres-fdw.sgml | 15 | ||||
-rw-r--r-- | src/backend/access/transam/xact.c | 28 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_backup_directory.c | 11 | ||||
-rw-r--r-- | src/include/access/xact.h | 1 |
7 files changed, 16 insertions, 350 deletions
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index caf14462696..304f3c20f83 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -58,7 +58,6 @@ typedef struct ConnCacheEntry /* Remaining fields are invalid when conn is NULL: */ int xact_depth; /* 0 = no xact open, 1 = main xact open, 2 = * one level of subxact open, etc */ - bool xact_read_only; /* xact r/o state */ bool have_prep_stmt; /* have we prepared any stmts in this xact? */ bool have_error; /* have any subxacts aborted in this xact? */ bool changing_xact_state; /* xact state change in process */ @@ -85,12 +84,6 @@ static unsigned int prep_stmt_number = 0; /* tracks whether any work is needed in callback functions */ static bool xact_got_connection = false; -/* - * tracks the nesting level of the topmost read-only transaction determined - * by GetTopReadOnlyTransactionNestLevel() - */ -static int top_read_only_level = 0; - /* custom wait event values, retrieved from shared memory */ static uint32 pgfdw_we_cleanup_result = 0; static uint32 pgfdw_we_connect = 0; @@ -379,7 +372,6 @@ make_new_connection(ConnCacheEntry *entry, UserMapping *user) /* Reset all transient state fields, to be sure all are clean */ entry->xact_depth = 0; - entry->xact_read_only = false; entry->have_prep_stmt = false; entry->have_error = false; entry->changing_xact_state = false; @@ -851,81 +843,29 @@ do_sql_command_end(PGconn *conn, const char *sql, bool consume_input) * those scans. A disadvantage is that we can't provide sane emulation of * READ COMMITTED behavior --- it would be nice if we had some other way to * control which remote queries share a snapshot. - * - * Note also that we always start the remote transaction with the same - * read/write and deferrable properties as the local transaction, and start - * the remote subtransaction with the same read/write property as the local - * subtransaction. */ static void begin_remote_xact(ConnCacheEntry *entry) { int curlevel = GetCurrentTransactionNestLevel(); - /* - * Set the nesting level of the topmost read-only transaction if the - * current transaction is read-only and we haven't yet. Once it's set, - * it's retained until that transaction is committed/aborted, and then - * reset (see pgfdw_xact_callback and pgfdw_subxact_callback). - */ - if (XactReadOnly) - { - if (top_read_only_level == 0) - top_read_only_level = GetTopReadOnlyTransactionNestLevel(); - Assert(top_read_only_level > 0); - } - else - Assert(top_read_only_level == 0); - - /* - * Start main transaction if we haven't yet; otherwise, change the - * already-started remote transaction/subtransaction to read-only if the - * local transaction/subtransaction have been done so after starting them - * and we haven't yet. - */ + /* Start main transaction if we haven't yet */ if (entry->xact_depth <= 0) { - StringInfoData sql; - bool ro = (top_read_only_level == 1); + const char *sql; elog(DEBUG3, "starting remote transaction on connection %p", entry->conn); - initStringInfo(&sql); - appendStringInfoString(&sql, "START TRANSACTION ISOLATION LEVEL "); if (IsolationIsSerializable()) - appendStringInfoString(&sql, "SERIALIZABLE"); + sql = "START TRANSACTION ISOLATION LEVEL SERIALIZABLE"; else - appendStringInfoString(&sql, "REPEATABLE READ"); - if (ro) - appendStringInfoString(&sql, " READ ONLY"); - if (XactDeferrable) - appendStringInfoString(&sql, " DEFERRABLE"); + sql = "START TRANSACTION ISOLATION LEVEL REPEATABLE READ"; entry->changing_xact_state = true; - do_sql_command(entry->conn, sql.data); + do_sql_command(entry->conn, sql); entry->xact_depth = 1; - if (ro) - { - Assert(!entry->xact_read_only); - entry->xact_read_only = true; - } entry->changing_xact_state = false; } - else if (!entry->xact_read_only) - { - Assert(top_read_only_level == 0 || - entry->xact_depth <= top_read_only_level); - if (entry->xact_depth == top_read_only_level) - { - entry->changing_xact_state = true; - do_sql_command(entry->conn, "SET transaction_read_only = on"); - entry->xact_read_only = true; - entry->changing_xact_state = false; - } - } - else - Assert(top_read_only_level > 0 && - entry->xact_depth >= top_read_only_level); /* * If we're in a subtransaction, stack up savepoints to match our level. @@ -934,21 +874,12 @@ begin_remote_xact(ConnCacheEntry *entry) */ while (entry->xact_depth < curlevel) { - StringInfoData sql; - bool ro = (entry->xact_depth + 1 == top_read_only_level); + char sql[64]; - initStringInfo(&sql); - appendStringInfo(&sql, "SAVEPOINT s%d", entry->xact_depth + 1); - if (ro) - appendStringInfoString(&sql, "; SET transaction_read_only = on"); + snprintf(sql, sizeof(sql), "SAVEPOINT s%d", entry->xact_depth + 1); entry->changing_xact_state = true; - do_sql_command(entry->conn, sql.data); + do_sql_command(entry->conn, sql); entry->xact_depth++; - if (ro) - { - Assert(!entry->xact_read_only); - entry->xact_read_only = true; - } entry->changing_xact_state = false; } } @@ -1243,9 +1174,6 @@ pgfdw_xact_callback(XactEvent event, void *arg) /* Also reset cursor numbering for next transaction */ cursor_number = 0; - - /* Likewise for top_read_only_level */ - top_read_only_level = 0; } /* @@ -1344,10 +1272,6 @@ pgfdw_subxact_callback(SubXactEvent event, SubTransactionId mySubid, false); } } - - /* If in the topmost read-only transaction, reset top_read_only_level */ - if (curlevel == top_read_only_level) - top_read_only_level = 0; } /* @@ -1450,9 +1374,6 @@ pgfdw_reset_xact_state(ConnCacheEntry *entry, bool toplevel) /* Reset state to show we're out of a transaction */ entry->xact_depth = 0; - /* Reset xact r/o state */ - entry->xact_read_only = false; - /* * If the connection isn't in a good idle state, it is marked as * invalid or keep_connections option of its server is disabled, then @@ -1473,10 +1394,6 @@ pgfdw_reset_xact_state(ConnCacheEntry *entry, bool toplevel) { /* Reset state to show we're out of a subtransaction */ entry->xact_depth--; - - /* If in the topmost read-only transaction, reset xact r/o state */ - if (entry->xact_depth + 1 == top_read_only_level) - entry->xact_read_only = false; } } diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index eb4716bed81..2185b42bb4f 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -12384,140 +12384,6 @@ SELECT count(*) FROM remote_application_name DROP FOREIGN TABLE remote_application_name; DROP VIEW my_application_name; -- =================================================================== --- test read-only and/or deferrable transactions --- =================================================================== -CREATE TABLE loct (f1 int, f2 text); -CREATE FUNCTION locf() RETURNS SETOF loct LANGUAGE SQL AS - 'UPDATE public.loct SET f2 = f2 || f2 RETURNING *'; -CREATE VIEW locv AS SELECT t.* FROM locf() t; -CREATE FOREIGN TABLE remt (f1 int, f2 text) - SERVER loopback OPTIONS (table_name 'locv'); -CREATE FOREIGN TABLE remt2 (f1 int, f2 text) - SERVER loopback2 OPTIONS (table_name 'locv'); -INSERT INTO loct VALUES (1, 'foo'), (2, 'bar'); -START TRANSACTION READ ONLY; -SAVEPOINT s; -SELECT * FROM remt; -- should fail -ERROR: cannot execute UPDATE in a read-only transaction -CONTEXT: SQL function "locf" statement 1 -remote SQL command: SELECT f1, f2 FROM public.locv -ROLLBACK TO s; -RELEASE SAVEPOINT s; -SELECT * FROM remt; -- should fail -ERROR: cannot execute UPDATE in a read-only transaction -CONTEXT: SQL function "locf" statement 1 -remote SQL command: SELECT f1, f2 FROM public.locv -ROLLBACK; -START TRANSACTION; -SAVEPOINT s; -SET transaction_read_only = on; -SELECT * FROM remt; -- should fail -ERROR: cannot execute UPDATE in a read-only transaction -CONTEXT: SQL function "locf" statement 1 -remote SQL command: SELECT f1, f2 FROM public.locv -ROLLBACK TO s; -RELEASE SAVEPOINT s; -SET transaction_read_only = on; -SELECT * FROM remt; -- should fail -ERROR: cannot execute UPDATE in a read-only transaction -CONTEXT: SQL function "locf" statement 1 -remote SQL command: SELECT f1, f2 FROM public.locv -ROLLBACK; -START TRANSACTION; -SAVEPOINT s; -SELECT * FROM remt; -- should work - f1 | f2 -----+-------- - 1 | foofoo - 2 | barbar -(2 rows) - -SET transaction_read_only = on; -SELECT * FROM remt; -- should fail -ERROR: cannot execute UPDATE in a read-only transaction -CONTEXT: SQL function "locf" statement 1 -remote SQL command: SELECT f1, f2 FROM public.locv -ROLLBACK TO s; -RELEASE SAVEPOINT s; -SELECT * FROM remt; -- should work - f1 | f2 -----+-------- - 1 | foofoo - 2 | barbar -(2 rows) - -SET transaction_read_only = on; -SELECT * FROM remt; -- should fail -ERROR: cannot execute UPDATE in a read-only transaction -CONTEXT: SQL function "locf" statement 1 -remote SQL command: SELECT f1, f2 FROM public.locv -ROLLBACK; -START TRANSACTION; -SAVEPOINT s; -SELECT * FROM remt; -- should work - f1 | f2 -----+-------- - 1 | foofoo - 2 | barbar -(2 rows) - -SET transaction_read_only = on; -SELECT * FROM remt2; -- should fail -ERROR: cannot execute UPDATE in a read-only transaction -CONTEXT: SQL function "locf" statement 1 -remote SQL command: SELECT f1, f2 FROM public.locv -ROLLBACK TO s; -RELEASE SAVEPOINT s; -SELECT * FROM remt; -- should work - f1 | f2 -----+-------- - 1 | foofoo - 2 | barbar -(2 rows) - -SET transaction_read_only = on; -SELECT * FROM remt2; -- should fail -ERROR: cannot execute UPDATE in a read-only transaction -CONTEXT: SQL function "locf" statement 1 -remote SQL command: SELECT f1, f2 FROM public.locv -ROLLBACK; -DROP FOREIGN TABLE remt; -CREATE FOREIGN TABLE remt (f1 int, f2 text) - SERVER loopback OPTIONS (table_name 'loct'); -START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY; -SELECT * FROM remt; - f1 | f2 -----+----- - 1 | foo - 2 | bar -(2 rows) - -COMMIT; -START TRANSACTION ISOLATION LEVEL SERIALIZABLE DEFERRABLE; -SELECT * FROM remt; - f1 | f2 -----+----- - 1 | foo - 2 | bar -(2 rows) - -COMMIT; -START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE; -SELECT * FROM remt; - f1 | f2 -----+----- - 1 | foo - 2 | bar -(2 rows) - -COMMIT; --- Clean up -DROP FOREIGN TABLE remt; -DROP FOREIGN TABLE remt2; -DROP VIEW locv; -DROP FUNCTION locf(); -DROP TABLE loct; --- =================================================================== -- test parallel commit and parallel abort -- =================================================================== ALTER SERVER loopback OPTIONS (ADD parallel_commit 'true'); diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 20a535b99d8..e534b40de3c 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -4201,84 +4201,6 @@ DROP FOREIGN TABLE remote_application_name; DROP VIEW my_application_name; -- =================================================================== --- test read-only and/or deferrable transactions --- =================================================================== -CREATE TABLE loct (f1 int, f2 text); -CREATE FUNCTION locf() RETURNS SETOF loct LANGUAGE SQL AS - 'UPDATE public.loct SET f2 = f2 || f2 RETURNING *'; -CREATE VIEW locv AS SELECT t.* FROM locf() t; -CREATE FOREIGN TABLE remt (f1 int, f2 text) - SERVER loopback OPTIONS (table_name 'locv'); -CREATE FOREIGN TABLE remt2 (f1 int, f2 text) - SERVER loopback2 OPTIONS (table_name 'locv'); -INSERT INTO loct VALUES (1, 'foo'), (2, 'bar'); - -START TRANSACTION READ ONLY; -SAVEPOINT s; -SELECT * FROM remt; -- should fail -ROLLBACK TO s; -RELEASE SAVEPOINT s; -SELECT * FROM remt; -- should fail -ROLLBACK; - -START TRANSACTION; -SAVEPOINT s; -SET transaction_read_only = on; -SELECT * FROM remt; -- should fail -ROLLBACK TO s; -RELEASE SAVEPOINT s; -SET transaction_read_only = on; -SELECT * FROM remt; -- should fail -ROLLBACK; - -START TRANSACTION; -SAVEPOINT s; -SELECT * FROM remt; -- should work -SET transaction_read_only = on; -SELECT * FROM remt; -- should fail -ROLLBACK TO s; -RELEASE SAVEPOINT s; -SELECT * FROM remt; -- should work -SET transaction_read_only = on; -SELECT * FROM remt; -- should fail -ROLLBACK; - -START TRANSACTION; -SAVEPOINT s; -SELECT * FROM remt; -- should work -SET transaction_read_only = on; -SELECT * FROM remt2; -- should fail -ROLLBACK TO s; -RELEASE SAVEPOINT s; -SELECT * FROM remt; -- should work -SET transaction_read_only = on; -SELECT * FROM remt2; -- should fail -ROLLBACK; - -DROP FOREIGN TABLE remt; -CREATE FOREIGN TABLE remt (f1 int, f2 text) - SERVER loopback OPTIONS (table_name 'loct'); - -START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY; -SELECT * FROM remt; -COMMIT; - -START TRANSACTION ISOLATION LEVEL SERIALIZABLE DEFERRABLE; -SELECT * FROM remt; -COMMIT; - -START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE; -SELECT * FROM remt; -COMMIT; - --- Clean up -DROP FOREIGN TABLE remt; -DROP FOREIGN TABLE remt2; -DROP VIEW locv; -DROP FUNCTION locf(); -DROP TABLE loct; - --- =================================================================== -- test parallel commit and parallel abort -- =================================================================== ALTER SERVER loopback OPTIONS (ADD parallel_commit 'true'); diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml index c464716e3ce..781a01067f7 100644 --- a/doc/src/sgml/postgres-fdw.sgml +++ b/doc/src/sgml/postgres-fdw.sgml @@ -1078,21 +1078,6 @@ postgres=# SELECT postgres_fdw_disconnect_all(); </para> <para> - The remote transaction is opened in the same read/write mode as the local - transaction: if the local transaction is <literal>READ ONLY</literal>, - the remote transaction is opened in <literal>READ ONLY</literal> mode, - otherwise it is opened in <literal>READ WRITE</literal> mode. - (This rule is also applied to remote and local subtransactions.) - </para> - - <para> - The remote transaction is also opened in the same deferrable mode as the - local transaction: if the local transaction is <literal>DEFERRABLE</literal>, - the remote transaction is opened in <literal>DEFERRABLE</literal> mode, - otherwise it is opened in <literal>NOT DEFERRABLE</literal> mode. - </para> - - <para> Note that it is currently not supported by <filename>postgres_fdw</filename> to prepare the remote transaction for two-phase commit. diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 2e67e998adb..b885513f765 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -1045,34 +1045,6 @@ TransactionStartedDuringRecovery(void) } /* - * GetTopReadOnlyTransactionNestLevel - * - * Note: this will return zero when not inside any transaction or when neither - * a top-level transaction nor subtransactions are read-only, one when the - * top-level transaction is read-only, two when one level of subtransaction is - * read-only, etc. - * - * Note: subtransactions of the topmost read-only transaction are also - * read-only, because they inherit read-only mode from the transaction, and - * thus can't change to read-write mode. See check_transaction_read_only(). - */ -int -GetTopReadOnlyTransactionNestLevel(void) -{ - TransactionState s = CurrentTransactionState; - - if (!XactReadOnly) - return 0; - while (s->nestingLevel > 1) - { - if (!s->prevXactReadOnly) - return s->nestingLevel; - s = s->parent; - } - return s->nestingLevel; -} - -/* * EnterParallelMode */ void diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c index 21b00792a8a..bc2a2fb4797 100644 --- a/src/bin/pg_dump/pg_backup_directory.c +++ b/src/bin/pg_dump/pg_backup_directory.c @@ -412,10 +412,15 @@ _LoadLOs(ArchiveHandle *AH, TocEntry *te) /* * Note: before archive v16, there was always only one BLOBS TOC entry, - * now there can be multiple. We don't need to worry what version we are - * reading though, because tctx->filename should be correct either way. + * now there can be multiple. Furthermore, although the actual filename + * was always "blobs.toc" before v16, the value of tctx->filename did not + * match that before commit 548e50976 fixed it. For simplicity we assume + * it must be "blobs.toc" in all archives before v16. */ - setFilePath(AH, tocfname, tctx->filename); + if (AH->version < K_VERS_1_16) + setFilePath(AH, tocfname, "blobs.toc"); + else + setFilePath(AH, tocfname, tctx->filename); CFH = ctx->LOsTocFH = InitDiscoverCompressFileHandle(tocfname, PG_BINARY_R); diff --git a/src/include/access/xact.h b/src/include/access/xact.h index 7f11b919799..b2bc10ee041 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -458,7 +458,6 @@ extern TimestampTz GetCurrentTransactionStopTimestamp(void); extern void SetCurrentStatementStartTimestamp(void); extern int GetCurrentTransactionNestLevel(void); extern bool TransactionIdIsCurrentTransactionId(TransactionId xid); -extern int GetTopReadOnlyTransactionNestLevel(void); extern void CommandCounterIncrement(void); extern void ForceSyncCommit(void); extern void StartTransactionCommand(void); |