aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/twophase.c11
-rw-r--r--src/backend/access/transam/varsup.c11
-rw-r--r--src/backend/utils/misc/guc.c4
-rw-r--r--src/backend/utils/misc/postgresql.conf.sample4
-rw-r--r--src/test/regress/expected/prepared_xacts.out2
-rw-r--r--src/test/regress/expected/prepared_xacts_1.out223
-rw-r--r--src/test/regress/pg_regress.c34
-rw-r--r--src/test/regress/sql/prepared_xacts.sql1
8 files changed, 270 insertions, 20 deletions
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index b738a4cef46..4685ccdf10b 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.51 2009/01/01 17:23:36 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.52 2009/04/23 00:23:45 tgl Exp $
*
* NOTES
* Each global transaction is associated with a global transaction
@@ -68,7 +68,7 @@
#define TWOPHASE_DIR "pg_twophase"
/* GUC variable, can't be changed after startup */
-int max_prepared_xacts = 5;
+int max_prepared_xacts = 0;
/*
* This struct describes one global transaction that is in prepared state
@@ -228,6 +228,13 @@ MarkAsPreparing(TransactionId xid, const char *gid,
errmsg("transaction identifier \"%s\" is too long",
gid)));
+ /* fail immediately if feature is disabled */
+ if (max_prepared_xacts == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("prepared transactions are disabled"),
+ errhint("Set max_prepared_transactions to a nonzero value.")));
+
LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);
/*
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index 5c0e6279877..029b2f2deb7 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -6,7 +6,7 @@
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.83 2009/01/01 17:23:36 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.84 2009/04/23 00:23:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -86,14 +86,16 @@ GetNewTransactionId(bool isSubXact)
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("database is not accepting commands to avoid wraparound data loss in database \"%s\"",
NameStr(ShmemVariableCache->limit_datname)),
- errhint("Stop the postmaster and use a standalone backend to vacuum database \"%s\".",
+ errhint("Stop the postmaster and use a standalone backend to vacuum database \"%s\".\n"
+ "You might also need to commit or roll back old prepared transactions.",
NameStr(ShmemVariableCache->limit_datname))));
else if (TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidWarnLimit))
ereport(WARNING,
(errmsg("database \"%s\" must be vacuumed within %u transactions",
NameStr(ShmemVariableCache->limit_datname),
ShmemVariableCache->xidWrapLimit - xid),
- errhint("To avoid a database shutdown, execute a database-wide VACUUM in \"%s\".",
+ errhint("To avoid a database shutdown, execute a database-wide VACUUM in \"%s\".\n"
+ "You might also need to commit or roll back old prepared transactions.",
NameStr(ShmemVariableCache->limit_datname))));
}
@@ -299,7 +301,8 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
(errmsg("database \"%s\" must be vacuumed within %u transactions",
NameStr(*oldest_datname),
xidWrapLimit - curXid),
- errhint("To avoid a database shutdown, execute a database-wide VACUUM in \"%s\".",
+ errhint("To avoid a database shutdown, execute a database-wide VACUUM in \"%s\".\n"
+ "You might also need to commit or roll back old prepared transactions.",
NameStr(*oldest_datname))));
}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 7313dc0e585..23fb43647d1 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.502 2009/04/07 23:27:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.503 2009/04/23 00:23:45 tgl Exp $
*
*--------------------------------------------------------------------
*/
@@ -1504,7 +1504,7 @@ static struct config_int ConfigureNamesInt[] =
NULL
},
&max_prepared_xacts,
- 5, 0, INT_MAX, NULL, NULL
+ 0, 0, INT_MAX / 4, NULL, NULL
},
#ifdef LOCK_DEBUG
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 1e9379ac2f1..3f7b43f0ccc 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -106,10 +106,12 @@
#shared_buffers = 32MB # min 128kB
# (change requires restart)
#temp_buffers = 8MB # min 800kB
-#max_prepared_transactions = 5 # can be 0 or more
+#max_prepared_transactions = 0 # zero disables the feature
# (change requires restart)
# Note: Increasing max_prepared_transactions costs ~600 bytes of shared memory
# per transaction slot, plus lock space (see max_locks_per_transaction).
+# It is not advisable to set max_prepared_transactions nonzero unless you
+# actively intend to use prepared transactions.
#work_mem = 1MB # min 64kB
#maintenance_work_mem = 16MB # min 1MB
#max_stack_depth = 2MB # min 100kB
diff --git a/src/test/regress/expected/prepared_xacts.out b/src/test/regress/expected/prepared_xacts.out
index 535dbe4cbf5..292962ab7b3 100644
--- a/src/test/regress/expected/prepared_xacts.out
+++ b/src/test/regress/expected/prepared_xacts.out
@@ -214,4 +214,6 @@ SELECT gid FROM pg_prepared_xacts;
-- Clean up
DROP TABLE pxtest2;
+DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled
+ERROR: table "pxtest3" does not exist
DROP TABLE pxtest4;
diff --git a/src/test/regress/expected/prepared_xacts_1.out b/src/test/regress/expected/prepared_xacts_1.out
new file mode 100644
index 00000000000..991a11bdfa9
--- /dev/null
+++ b/src/test/regress/expected/prepared_xacts_1.out
@@ -0,0 +1,223 @@
+--
+-- PREPARED TRANSACTIONS (two-phase commit)
+--
+-- We can't readily test persistence of prepared xacts within the
+-- regression script framework, unfortunately. Note that a crash
+-- isn't really needed ... stopping and starting the postmaster would
+-- be enough, but we can't even do that here.
+-- create a simple table that we'll use in the tests
+CREATE TABLE pxtest1 (foobar VARCHAR(10));
+INSERT INTO pxtest1 VALUES ('aaa');
+-- Test PREPARE TRANSACTION
+BEGIN;
+UPDATE pxtest1 SET foobar = 'bbb' WHERE foobar = 'aaa';
+SELECT * FROM pxtest1;
+ foobar
+--------
+ bbb
+(1 row)
+
+PREPARE TRANSACTION 'foo1';
+ERROR: prepared transactions are disabled
+HINT: Set max_prepared_transactions to a nonzero value.
+SELECT * FROM pxtest1;
+ foobar
+--------
+ aaa
+(1 row)
+
+-- Test pg_prepared_xacts system view
+SELECT gid FROM pg_prepared_xacts;
+ gid
+-----
+(0 rows)
+
+-- Test ROLLBACK PREPARED
+ROLLBACK PREPARED 'foo1';
+ERROR: prepared transaction with identifier "foo1" does not exist
+SELECT * FROM pxtest1;
+ foobar
+--------
+ aaa
+(1 row)
+
+SELECT gid FROM pg_prepared_xacts;
+ gid
+-----
+(0 rows)
+
+-- Test COMMIT PREPARED
+BEGIN;
+INSERT INTO pxtest1 VALUES ('ddd');
+SELECT * FROM pxtest1;
+ foobar
+--------
+ aaa
+ ddd
+(2 rows)
+
+PREPARE TRANSACTION 'foo2';
+ERROR: prepared transactions are disabled
+HINT: Set max_prepared_transactions to a nonzero value.
+SELECT * FROM pxtest1;
+ foobar
+--------
+ aaa
+(1 row)
+
+COMMIT PREPARED 'foo2';
+ERROR: prepared transaction with identifier "foo2" does not exist
+SELECT * FROM pxtest1;
+ foobar
+--------
+ aaa
+(1 row)
+
+-- Test duplicate gids
+BEGIN;
+UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd';
+SELECT * FROM pxtest1;
+ foobar
+--------
+ aaa
+(1 row)
+
+PREPARE TRANSACTION 'foo3';
+ERROR: prepared transactions are disabled
+HINT: Set max_prepared_transactions to a nonzero value.
+SELECT gid FROM pg_prepared_xacts;
+ gid
+-----
+(0 rows)
+
+BEGIN;
+INSERT INTO pxtest1 VALUES ('fff');
+SELECT * FROM pxtest1;
+ foobar
+--------
+ aaa
+ fff
+(2 rows)
+
+-- This should fail, because the gid foo3 is already in use
+PREPARE TRANSACTION 'foo3';
+ERROR: prepared transactions are disabled
+HINT: Set max_prepared_transactions to a nonzero value.
+SELECT * FROM pxtest1;
+ foobar
+--------
+ aaa
+(1 row)
+
+ROLLBACK PREPARED 'foo3';
+ERROR: prepared transaction with identifier "foo3" does not exist
+SELECT * FROM pxtest1;
+ foobar
+--------
+ aaa
+(1 row)
+
+-- Clean up
+DROP TABLE pxtest1;
+-- Test subtransactions
+BEGIN;
+ CREATE TABLE pxtest2 (a int);
+ INSERT INTO pxtest2 VALUES (1);
+ SAVEPOINT a;
+ INSERT INTO pxtest2 VALUES (2);
+ ROLLBACK TO a;
+ SAVEPOINT b;
+ INSERT INTO pxtest2 VALUES (3);
+PREPARE TRANSACTION 'regress-one';
+ERROR: prepared transactions are disabled
+HINT: Set max_prepared_transactions to a nonzero value.
+CREATE TABLE pxtest3(fff int);
+-- Test shared invalidation
+BEGIN;
+ DROP TABLE pxtest3;
+ CREATE TABLE pxtest4 (a int);
+ INSERT INTO pxtest4 VALUES (1);
+ INSERT INTO pxtest4 VALUES (2);
+ DECLARE foo CURSOR FOR SELECT * FROM pxtest4;
+ -- Fetch 1 tuple, keeping the cursor open
+ FETCH 1 FROM foo;
+ a
+---
+ 1
+(1 row)
+
+PREPARE TRANSACTION 'regress-two';
+ERROR: prepared transactions are disabled
+HINT: Set max_prepared_transactions to a nonzero value.
+-- No such cursor
+FETCH 1 FROM foo;
+ERROR: cursor "foo" does not exist
+-- Table doesn't exist, the creation hasn't been committed yet
+SELECT * FROM pxtest2;
+ERROR: relation "pxtest2" does not exist
+LINE 1: SELECT * FROM pxtest2;
+ ^
+-- There should be two prepared transactions
+SELECT gid FROM pg_prepared_xacts;
+ gid
+-----
+(0 rows)
+
+-- pxtest3 should be locked because of the pending DROP
+set statement_timeout to 2000;
+SELECT * FROM pxtest3;
+ fff
+-----
+(0 rows)
+
+reset statement_timeout;
+-- Disconnect, we will continue testing in a different backend
+\c -
+-- There should still be two prepared transactions
+SELECT gid FROM pg_prepared_xacts;
+ gid
+-----
+(0 rows)
+
+-- pxtest3 should still be locked because of the pending DROP
+set statement_timeout to 2000;
+SELECT * FROM pxtest3;
+ fff
+-----
+(0 rows)
+
+reset statement_timeout;
+-- Commit table creation
+COMMIT PREPARED 'regress-one';
+ERROR: prepared transaction with identifier "regress-one" does not exist
+\d pxtest2
+SELECT * FROM pxtest2;
+ERROR: relation "pxtest2" does not exist
+LINE 1: SELECT * FROM pxtest2;
+ ^
+-- There should be one prepared transaction
+SELECT gid FROM pg_prepared_xacts;
+ gid
+-----
+(0 rows)
+
+-- Commit table drop
+COMMIT PREPARED 'regress-two';
+ERROR: prepared transaction with identifier "regress-two" does not exist
+SELECT * FROM pxtest3;
+ fff
+-----
+(0 rows)
+
+-- There should be no prepared transactions
+SELECT gid FROM pg_prepared_xacts;
+ gid
+-----
+(0 rows)
+
+-- Clean up
+DROP TABLE pxtest2;
+ERROR: table "pxtest2" does not exist
+DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled
+DROP TABLE pxtest4;
+ERROR: table "pxtest4" does not exist
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index 7bd297f20c1..b51d6ec2b5b 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/test/regress/pg_regress.c,v 1.61 2009/02/12 13:26:03 petere Exp $
+ * $PostgreSQL: pgsql/src/test/regress/pg_regress.c,v 1.62 2009/04/23 00:23:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2037,6 +2037,8 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
if (temp_install)
{
+ FILE *pg_conf;
+
/*
* Prepare the temp installation
*/
@@ -2092,20 +2094,29 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
exit_nicely(2);
}
- /* add any extra config specified to the postgresql.conf */
+ /*
+ * Adjust the default postgresql.conf as needed for regression testing.
+ * The user can specify a file to be appended; in any case we set
+ * max_prepared_transactions to enable testing of prepared xacts.
+ * (Note: to reduce the probability of unexpected shmmax failures,
+ * don't set max_prepared_transactions any higher than actually
+ * needed by the prepared_xacts regression test.)
+ */
+ snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install);
+ pg_conf = fopen(buf, "a");
+ if (pg_conf == NULL)
+ {
+ fprintf(stderr, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname, buf, strerror(errno));
+ exit_nicely(2);
+ }
+ fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
+ fputs("max_prepared_transactions = 2\n", pg_conf);
+
if (temp_config != NULL)
{
FILE *extra_conf;
- FILE *pg_conf;
char line_buf[1024];
- snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install);
- pg_conf = fopen(buf, "a");
- if (pg_conf == NULL)
- {
- fprintf(stderr, _("\n%s: could not open \"%s\" for adding extra config: %s\n"), progname, buf, strerror(errno));
- exit_nicely(2);
- }
extra_conf = fopen(temp_config, "r");
if (extra_conf == NULL)
{
@@ -2115,9 +2126,10 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
fputs(line_buf, pg_conf);
fclose(extra_conf);
- fclose(pg_conf);
}
+ fclose(pg_conf);
+
/*
* Check if there is a postmaster running already.
*/
diff --git a/src/test/regress/sql/prepared_xacts.sql b/src/test/regress/sql/prepared_xacts.sql
index 337567271de..39d323a15b6 100644
--- a/src/test/regress/sql/prepared_xacts.sql
+++ b/src/test/regress/sql/prepared_xacts.sql
@@ -134,4 +134,5 @@ SELECT gid FROM pg_prepared_xacts;
-- Clean up
DROP TABLE pxtest2;
+DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled
DROP TABLE pxtest4;