Re: Transactions and temp tables

Поиск
Список
Период
Сортировка
От Emmanuel Cecchet
Тема Re: Transactions and temp tables
Дата
Msg-id 48EFA13C.2060407@frogthinker.org
обсуждение исходный текст
Ответ на Re: Transactions and temp tables  (Tom Lane <tgl@sss.pgh.pa.us>)
Ответы Re: Transactions and temp tables  (Emmanuel Cecchet <manu@frogthinker.org>)
Re: Transactions and temp tables  (Heikki Linnakangas <heikki.linnakangas@enterprisedb.com>)
Список pgsql-hackers
Hi all,

Here is the latest patch and the regression tests for the temp tables
and 2PC issue.
Is there a way to stop and restart postmaster between 2 tests?

Thanks for your feedback,
Emmanuel

--
Emmanuel Cecchet
FTO @ Frog Thinker
Open Source Development & Consulting
--
Web: http://www.frogthinker.org
email: manu@frogthinker.org
Skype: emmanuel_cecchet

### Eclipse Workspace Patch 1.0
#P Postgres-HEAD
Index: src/test/regress/parallel_schedule
===================================================================
RCS file: /root/cvsrepo/pgsql/src/test/regress/parallel_schedule,v
retrieving revision 1.49
diff -u -r1.49 parallel_schedule
--- src/test/regress/parallel_schedule    4 Oct 2008 21:56:55 -0000    1.49
+++ src/test/regress/parallel_schedule    10 Oct 2008 18:33:01 -0000
@@ -90,3 +90,19 @@

 # run tablespace by itself
 test: tablespace
+
+# --------
+# 2PC related tests
+# --------
+test: 2pc_persistent_table 2pc_on_delete_rows_transaction 2pc_on_commit_drop 2pc_temp_table_transaction
2pc_temp_table_rollback2pc_temp_table_savepoint 2pc_temp_table_failure 
+test: 2pc_dirty_buffer_check
+test: 2pc_temp_table_session
+test: 2pc_on_delete_rows_session
+# The following tests must be executing in sequence,
+# do not alter the order nor try to execute them in parallel
+test: 2pc_temp_table_prepared_not_committed
+test: 2pc_temp_table_commit_prepared
+# This test must be run last to check if the database properly
+# shutdowns with a prepared transaction that is not committed
+test: 2pc_temp_table_prepared_not_committed
+
\ No newline at end of file
Index: src/test/regress/serial_schedule
===================================================================
RCS file: /root/cvsrepo/pgsql/src/test/regress/serial_schedule,v
retrieving revision 1.46
diff -u -r1.46 serial_schedule
--- src/test/regress/serial_schedule    4 Oct 2008 21:56:55 -0000    1.46
+++ src/test/regress/serial_schedule    10 Oct 2008 18:33:01 -0000
@@ -118,3 +118,20 @@
 test: xml
 test: stats
 test: tablespace
+test: 2pc_persistent_table
+test: 2pc_on_delete_rows_transaction
+test: 2pc_on_commit_drop
+test: 2pc_temp_table_transaction
+test: 2pc_temp_table_rollback
+test: 2pc_temp_table_savepoint
+test: 2pc_dirty_buffer_check
+test: 2pc_temp_table_session
+test: 2pc_on_delete_rows_session
+test: 2pc_temp_table_failure
+# The following tests must be executing in sequence,
+# do not alter the order nor try to execute them in parallel
+test: 2pc_temp_table_prepared_not_committed
+test: 2pc_temp_table_commit_prepared
+# This test must be run last to check if the database properly
+# shutdowns with a prepared transaction that is not committed
+test: 2pc_temp_table_prepared_not_committed
Index: src/test/regress/expected/2pc_temp_table_failure.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_failure.out
diff -N src/test/regress/expected/2pc_temp_table_failure.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_failure.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,8 @@
+-- Existing non-empty temp table at commit time should still fail
+begin;
+create temp table foo(x int);
+insert into foo values(1);
+prepare transaction 'existingTempTableShouldFail';
+ERROR:  cannot PREPARE a transaction that has operated on temporary tables that are not empty at commit time
+commit prepared 'existingTempTableShouldFail';
+ERROR:  prepared transaction with identifier "existingTempTableShouldFail" does not exist
Index: src/test/regress/expected/2pc_temp_table_commit_prepared.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_commit_prepared.out
diff -N src/test/regress/expected/2pc_temp_table_commit_prepared.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_commit_prepared.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,8 @@
+-- The purpose of this test is to test the proper termination of
+-- a session with a prepared transaction that has accessed a temp table
+--
+-- This test has to be called in sequence after 2pc_temp_table_prepared_not_committed.sql
+commit prepared 'preparedNonCommittedFoo';
+-- The table should not exist anymore in this session
+drop table foo;
+ERROR:  table "foo" does not exist
Index: src/test/regress/expected/2pc_on_delete_rows_session.out
===================================================================
RCS file: src/test/regress/expected/2pc_on_delete_rows_session.out
diff -N src/test/regress/expected/2pc_on_delete_rows_session.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_on_delete_rows_session.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,7 @@
+-- Temp table with ON DELETE ROWS option (session scope)
+create temp table foo(x int) on commit delete rows;
+begin;
+insert into foo values(1);
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+drop table foo;
Index: src/test/regress/expected/2pc_temp_table_savepoint.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_savepoint.out
diff -N src/test/regress/expected/2pc_temp_table_savepoint.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_savepoint.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,8 @@
+-- Rollback to savepoint test case
+BEGIN;
+SAVEPOINT sp;
+CREATE TEMP TABLE foo(bar int4);
+INSERT INTO foo VALUES (1);
+ROLLBACK TO sp;
+PREPARE TRANSACTION 'savepointTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
+COMMIT PREPARED 'savepointTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
Index: src/test/regress/sql/2pc_dirty_buffer_check.sql
===================================================================
RCS file: src/test/regress/sql/2pc_dirty_buffer_check.sql
diff -N src/test/regress/sql/2pc_dirty_buffer_check.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_dirty_buffer_check.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,52 @@
+-- 2PC Dirty buffer check
+begin;
+create temp table foo(a int, b int, c int) on commit drop;
+insert into foo values(1,1,1);
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+prepare transaction 'bcd';
+commit prepared 'bcd';
+begin;
+create temp table bar(a int, b int, c int) on commit drop;
+insert into bar values(1,1,1);
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+commit;
Index: src/test/regress/expected/2pc_temp_table_transaction.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_transaction.out
diff -N src/test/regress/expected/2pc_temp_table_transaction.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_transaction.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,7 @@
+-- Transaction-scope dropped temp table use case
+begin;
+create temp table foo(x int);
+insert into foo values(1);
+drop table foo;
+prepare transaction 'dropTempTableShouldSucceed';
+commit prepared 'dropTempTableShouldSucceed';
Index: src/test/regress/sql/2pc_temp_table_rollback.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_rollback.sql
diff -N src/test/regress/sql/2pc_temp_table_rollback.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_rollback.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,5 @@
+-- Rollback prepared
+BEGIN;
+CREATE TEMP TABLE foo(bar int4);
+PREPARE TRANSACTION 'rollbackTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
+ROLLBACK PREPARED 'rollbackTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
Index: src/test/regress/sql/2pc_on_commit_drop.sql
===================================================================
RCS file: src/test/regress/sql/2pc_on_commit_drop.sql
diff -N src/test/regress/sql/2pc_on_commit_drop.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_on_commit_drop.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,6 @@
+-- Temp table with ON COMMIT DROP option
+begin;
+create temp table foo(x int) on commit drop;
+insert into foo values(1);
+prepare transaction 'onCommitDropTempTableShouldSucceed';
+commit prepared 'onCommitDropTempTableShouldSucceed';
Index: src/test/regress/expected/2pc_temp_table_prepared_not_committed.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_prepared_not_committed.out
diff -N src/test/regress/expected/2pc_temp_table_prepared_not_committed.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_prepared_not_committed.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,10 @@
+-- The purpose of this test is to test the proper termination of
+-- a session with a prepared transaction that has accessed a temp table
+--
+-- Session-scope temp table use case but exit after prepared
+-- see 2pc_temp_table_commit_prepared.sql for committing that transaction
+create temp table foo(x int);
+begin;
+insert into foo values(1);
+delete from foo;
+prepare transaction 'preparedNonCommittedFoo';
Index: src/test/regress/sql/2pc_on_delete_rows_transaction.sql
===================================================================
RCS file: src/test/regress/sql/2pc_on_delete_rows_transaction.sql
diff -N src/test/regress/sql/2pc_on_delete_rows_transaction.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_on_delete_rows_transaction.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,7 @@
+-- Temp table with ON DELETE ROWS option (transaction scope)
+begin;
+create temp table foo(x int) on commit delete rows;
+insert into foo values(1);
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+drop table foo;
Index: src/test/regress/expected/2pc_dirty_buffer_check.out
===================================================================
RCS file: src/test/regress/expected/2pc_dirty_buffer_check.out
diff -N src/test/regress/expected/2pc_dirty_buffer_check.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_dirty_buffer_check.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,52 @@
+-- 2PC Dirty buffer check
+begin;
+create temp table foo(a int, b int, c int) on commit drop;
+insert into foo values(1,1,1);
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+insert into foo select * from foo;
+prepare transaction 'bcd';
+commit prepared 'bcd';
+begin;
+create temp table bar(a int, b int, c int) on commit drop;
+insert into bar values(1,1,1);
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+insert into bar select * from bar;
+commit;
Index: src/test/regress/sql/2pc_on_delete_rows_session.sql
===================================================================
RCS file: src/test/regress/sql/2pc_on_delete_rows_session.sql
diff -N src/test/regress/sql/2pc_on_delete_rows_session.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_on_delete_rows_session.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,7 @@
+-- Temp table with ON DELETE ROWS option (session scope)
+create temp table foo(x int) on commit delete rows;
+begin;
+insert into foo values(1);
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+drop table foo;
Index: src/test/regress/expected/2pc_on_commit_drop.out
===================================================================
RCS file: src/test/regress/expected/2pc_on_commit_drop.out
diff -N src/test/regress/expected/2pc_on_commit_drop.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_on_commit_drop.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,6 @@
+-- Temp table with ON COMMIT DROP option
+begin;
+create temp table foo(x int) on commit drop;
+insert into foo values(1);
+prepare transaction 'onCommitDropTempTableShouldSucceed';
+commit prepared 'onCommitDropTempTableShouldSucceed';
Index: src/test/regress/sql/2pc_temp_table_commit_prepared.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_commit_prepared.sql
diff -N src/test/regress/sql/2pc_temp_table_commit_prepared.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_commit_prepared.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,7 @@
+-- The purpose of this test is to test the proper termination of
+-- a session with a prepared transaction that has accessed a temp table
+--
+-- This test has to be called in sequence after 2pc_temp_table_prepared_not_committed.sql
+commit prepared 'preparedNonCommittedFoo';
+-- The table should not exist anymore in this session
+drop table foo;
Index: src/test/regress/expected/2pc_on_delete_rows_transaction.out
===================================================================
RCS file: src/test/regress/expected/2pc_on_delete_rows_transaction.out
diff -N src/test/regress/expected/2pc_on_delete_rows_transaction.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_on_delete_rows_transaction.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,7 @@
+-- Temp table with ON DELETE ROWS option (transaction scope)
+begin;
+create temp table foo(x int) on commit delete rows;
+insert into foo values(1);
+prepare transaction 'onCommitDeleteRowsTempTableShouldSucceed';
+commit prepared 'onCommitDeleteRowsTempTableShouldSucceed';
+drop table foo;
Index: src/test/regress/sql/2pc_temp_table_transaction.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_transaction.sql
diff -N src/test/regress/sql/2pc_temp_table_transaction.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_transaction.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,7 @@
+-- Transaction-scope dropped temp table use case
+begin;
+create temp table foo(x int);
+insert into foo values(1);
+drop table foo;
+prepare transaction 'dropTempTableShouldSucceed';
+commit prepared 'dropTempTableShouldSucceed';
Index: src/test/regress/sql/2pc_temp_table_prepared_not_committed.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_prepared_not_committed.sql
diff -N src/test/regress/sql/2pc_temp_table_prepared_not_committed.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_prepared_not_committed.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,10 @@
+-- The purpose of this test is to test the proper termination of
+-- a session with a prepared transaction that has accessed a temp table
+--
+-- Session-scope temp table use case but exit after prepared
+-- see 2pc_temp_table_commit_prepared.sql for committing that transaction
+create temp table foo(x int);
+begin;
+insert into foo values(1);
+delete from foo;
+prepare transaction 'preparedNonCommittedFoo';
Index: src/test/regress/sql/2pc_temp_table_savepoint.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_savepoint.sql
diff -N src/test/regress/sql/2pc_temp_table_savepoint.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_savepoint.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,8 @@
+-- Rollback to savepoint test case
+BEGIN;
+SAVEPOINT sp;
+CREATE TEMP TABLE foo(bar int4);
+INSERT INTO foo VALUES (1);
+ROLLBACK TO sp;
+PREPARE TRANSACTION 'savepointTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
+COMMIT PREPARED 'savepointTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
Index: src/test/regress/sql/2pc_persistent_table.sql
===================================================================
RCS file: src/test/regress/sql/2pc_persistent_table.sql
diff -N src/test/regress/sql/2pc_persistent_table.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_persistent_table.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,12 @@
+-- Creation of a persistent table (not temp)
+begin;
+create table paul(x int);
+insert into paul values(1);
+prepare transaction 'persistentTableShouldSucceed';
+commit prepared 'persistentTableShouldSucceed';
+
+-- Drop of a persistent table (not temp)
+begin;
+drop table paul;
+prepare transaction 'dropPersistentTableShouldSucceed';
+commit prepared 'dropPersistentTableShouldSucceed';
Index: src/test/regress/expected/2pc_persistent_table.out
===================================================================
RCS file: src/test/regress/expected/2pc_persistent_table.out
diff -N src/test/regress/expected/2pc_persistent_table.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_persistent_table.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,11 @@
+-- Creation of a persistent table (not temp)
+begin;
+create table paul(x int);
+insert into paul values(1);
+prepare transaction 'persistentTableShouldSucceed';
+commit prepared 'persistentTableShouldSucceed';
+-- Drop of a persistent table (not temp)
+begin;
+drop table paul;
+prepare transaction 'dropPersistentTableShouldSucceed';
+commit prepared 'dropPersistentTableShouldSucceed';
Index: src/test/regress/sql/2pc_temp_table_failure.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_failure.sql
diff -N src/test/regress/sql/2pc_temp_table_failure.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_failure.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,6 @@
+-- Existing non-empty temp table at commit time should still fail
+begin;
+create temp table foo(x int);
+insert into foo values(1);
+prepare transaction 'existingTempTableShouldFail';
+commit prepared 'existingTempTableShouldFail';
Index: src/test/regress/expected/2pc_temp_table_rollback.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_rollback.out
diff -N src/test/regress/expected/2pc_temp_table_rollback.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_rollback.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,5 @@
+-- Rollback prepared
+BEGIN;
+CREATE TEMP TABLE foo(bar int4);
+PREPARE TRANSACTION 'rollbackTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
+ROLLBACK PREPARED 'rollbackTestCase_archives.postgresql.org_pgsql-hackers_2008-03_msg00017.php';
Index: src/test/regress/expected/2pc_temp_table_session.out
===================================================================
RCS file: src/test/regress/expected/2pc_temp_table_session.out
diff -N src/test/regress/expected/2pc_temp_table_session.out
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/expected/2pc_temp_table_session.out    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,8 @@
+-- Session-scope temp table use case
+create temp table foo(x int);
+begin;
+insert into foo values(1);
+delete from foo;
+prepare transaction 'dropTempTableShouldSucceed';
+commit prepared 'dropTempTableShouldSucceed';
+drop table foo;
Index: src/test/regress/sql/2pc_temp_table_session.sql
===================================================================
RCS file: src/test/regress/sql/2pc_temp_table_session.sql
diff -N src/test/regress/sql/2pc_temp_table_session.sql
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/test/regress/sql/2pc_temp_table_session.sql    1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,8 @@
+-- Session-scope temp table use case
+create temp table foo(x int);
+begin;
+insert into foo values(1);
+delete from foo;
+prepare transaction 'dropTempTableShouldSucceed';
+commit prepared 'dropTempTableShouldSucceed';
+drop table foo;
### Eclipse Workspace Patch 1.0
#P Postgres-HEAD
Index: src/backend/access/heap/heapam.c
===================================================================
RCS file: /root/cvsrepo/pgsql/src/backend/access/heap/heapam.c,v
retrieving revision 1.264
diff -u -r1.264 heapam.c
--- src/backend/access/heap/heapam.c    30 Sep 2008 10:52:10 -0000    1.264
+++ src/backend/access/heap/heapam.c    9 Oct 2008 21:44:04 -0000
@@ -878,7 +878,7 @@

     /* Make note that we've accessed a temporary relation */
     if (r->rd_istemp)
-        MyXactAccessedTempRel = true;
+        enlistRelationIdFor2PCChecks(relationId);

     pgstat_initstats(r);

@@ -926,7 +926,7 @@

     /* Make note that we've accessed a temporary relation */
     if (r->rd_istemp)
-        MyXactAccessedTempRel = true;
+        enlistRelationIdFor2PCChecks(relationId);

     pgstat_initstats(r);

@@ -976,7 +976,7 @@

     /* Make note that we've accessed a temporary relation */
     if (r->rd_istemp)
-        MyXactAccessedTempRel = true;
+        enlistRelationIdFor2PCChecks(relationId);

     pgstat_initstats(r);

Index: src/backend/access/transam/xact.c
===================================================================
RCS file: /root/cvsrepo/pgsql/src/backend/access/transam/xact.c,v
retrieving revision 1.265
diff -u -r1.265 xact.c
--- src/backend/access/transam/xact.c    11 Aug 2008 11:05:10 -0000    1.265
+++ src/backend/access/transam/xact.c    9 Oct 2008 21:44:04 -0000
@@ -47,6 +47,7 @@
 #include "utils/memutils.h"
 #include "utils/relcache.h"
 #include "utils/snapmgr.h"
+#include "utils/tqual.h"
 #include "utils/xml.h"
 #include "pg_trace.h"

@@ -65,13 +66,6 @@
 int            CommitDelay = 0;    /* precommit delay in microseconds */
 int            CommitSiblings = 5; /* # concurrent xacts needed to sleep */

-/*
- * MyXactAccessedTempRel is set when a temporary relation is accessed.
- * We don't allow PREPARE TRANSACTION in that case.  (This is global
- * so that it can be set from heapam.c.)
- */
-bool        MyXactAccessedTempRel = false;
-

 /*
  *    transaction states - transaction state from server perspective
@@ -209,6 +203,13 @@
  */
 static MemoryContext TransactionAbortContext = NULL;

+/* Hash table containing Oids of accessed temporary relations */
+HTAB    *accessedTempRel;
+/* Hash table containing Oids of accessed temporary relations that have been
+ * prepared commit but not committed yet
+ */
+HTAB    *preparedTempRel;
+
 /*
  * List of add-on start- and end-of-xact callbacks
  */
@@ -250,6 +251,7 @@
                      SubTransactionId mySubid,
                      SubTransactionId parentSubid);
 static void CleanupTransaction(void);
+static void CleanupAccessedTempRel(void);
 static void CommitTransaction(void);
 static TransactionId RecordTransactionAbort(bool isSubXact);
 static void StartTransaction(void);
@@ -1511,7 +1513,6 @@
     XactIsoLevel = DefaultXactIsoLevel;
     XactReadOnly = DefaultXactReadOnly;
     forceSyncCommit = false;
-    MyXactAccessedTempRel = false;

     /*
      * reinitialize within-transaction counters
@@ -1760,6 +1761,8 @@

     AtCommit_Memory();

+    CleanupAccessedTempRel();
+
     s->transactionId = InvalidTransactionId;
     s->subTransactionId = InvalidSubTransactionId;
     s->nestingLevel = 0;
@@ -1777,6 +1780,74 @@
     RESUME_INTERRUPTS();
 }

+/* ----------------
+ *     enlistRelationIdFor2PCChecks - enlist a relation in the list of
+ *      resources to check at PREPARE COMMIT time if we are part of
+ *      a 2PC transaction. The resource will be removed from the list
+ *      if the table is dropped before commit.
+ * ----------------
+ */
+void
+enlistRelationIdFor2PCChecks(Oid relationId)
+{
+    Oid *tid;
+
+    /*
+     * Each time a temporary relation is accessed, it is added to the
+     * accessedTempRel list. PREPARE TRANSACTION will fail if any
+     * of the accessed relation is still valid (not dropped).  (This is
+     * called from from heapam.c.)
+     */
+    if (accessedTempRel == NULL)
+    { // Allocate the list on-demand
+        HASHCTL ctl;
+
+        ctl.keysize = sizeof(Oid);
+        ctl.entrysize = sizeof(Oid);
+        accessedTempRel = hash_create("accessed temp tables", 4, &ctl,
+                HASH_ELEM);
+    }
+
+    // Add to the hash list if missing
+    tid = hash_search(accessedTempRel, &relationId, HASH_ENTER, NULL);
+    *tid = relationId;
+}
+
+/*
+ * Cleanup the list of prepared temp tables that were accessed during this transaction.
+ */
+static void CleanupAccessedTempRel(void)
+{
+    if (accessedTempRel != NULL)
+    {
+        if (preparedTempRel != NULL)
+        { // We have prepared transactions with temp tables
+            HASH_SEQ_STATUS    status;
+            Oid*            tempTableOid;
+
+            hash_seq_init(&status, accessedTempRel);
+            while ((tempTableOid = (Oid *) hash_seq_search(&status)) != NULL)
+            { // Add all relations to the hash list
+                hash_search(preparedTempRel, tempTableOid, HASH_REMOVE, NULL);
+            }
+        }
+        hash_destroy(accessedTempRel);
+        accessedTempRel = NULL;
+    }
+}
+
+/*
+ * Returns true if the provided relationId is a temp table that has been
+ * prepared commit but not committed yet.
+ */
+bool
+isPreparedTempRelation(Oid relationId)
+{
+    if (preparedTempRel == NULL)
+        return false;
+
+    return hash_search(preparedTempRel, &relationId, HASH_FIND, NULL) != NULL;
+}

 /*
  *    PrepareTransaction
@@ -1853,14 +1924,61 @@
      * We must check this after executing any ON COMMIT actions, because
      * they might still access a temp relation.
      *
-     * XXX In principle this could be relaxed to allow some useful special
-     * cases, such as a temp table created and dropped all within the
-     * transaction.  That seems to require much more bookkeeping though.
+     * We only allow to proceed further if the accessed temp tables have
+     * been dropped before PREPARE COMMIT.
      */
-    if (MyXactAccessedTempRel)
-        ereport(ERROR,
-                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                 errmsg("cannot PREPARE a transaction that has operated on temporary tables")));
+    if (accessedTempRel != NULL)
+    {
+        HASH_SEQ_STATUS    status;
+        Oid*            tempTableOid;
+
+        /* Prevent further updates to the list as recommended in hash_seq_init doc. */
+        hash_freeze(accessedTempRel);
+        hash_seq_init(&status, accessedTempRel);
+        while ((tempTableOid = (Oid *) hash_seq_search(&status)) != NULL)
+        { /* Check all accessed temp tables. If the table has been dropped,
+           * try_relation_open will fail and we can safely continue. */
+            Relation tempTable = try_relation_open(*tempTableOid, NoLock);
+
+            if (tempTable != NULL)
+            { /* We have an open temp table at PREPARE COMMIT time. We
+               * will only accept empty temp tables and throw an error
+               * in other cases. */
+                HeapScanDesc scan;
+                HeapTuple tuple;
+                scan = heap_beginscan(tempTable, SnapshotNow, 0, NULL);
+                if ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+                {
+                    hash_seq_term(&status);
+                    hash_destroy(accessedTempRel);
+                    accessedTempRel = NULL;
+                    ereport(ERROR,
+                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                    errmsg("cannot PREPARE a transaction that has operated on temporary tables that
arenot empty at commit time"))); 
+                }
+                heap_endscan(scan);
+                relation_close(tempTable, NoLock);
+            }
+        }
+
+        // Success! All temp relations are empty, we need to add them to the list of prepared commit temp relations
+        if (preparedTempRel == NULL)
+        { // Create list if it does not exist yet
+            HASHCTL ctl;
+
+            ctl.keysize = sizeof(Oid);
+            ctl.entrysize = sizeof(Oid);
+            preparedTempRel = hash_create("prepared temp tables", 10, &ctl,
+                    HASH_ELEM);
+        }
+
+        hash_seq_init(&status, accessedTempRel);
+        while ((tempTableOid = (Oid *) hash_seq_search(&status)) != NULL)
+        { // Add all relations to the hash list
+            Oid *tid = hash_search(preparedTempRel, tempTableOid, HASH_ENTER, NULL);
+            *tid = *tempTableOid;
+        }
+    }

     /* Prevent cancel/die interrupt while cleaning up */
     HOLD_INTERRUPTS();
@@ -2151,6 +2269,14 @@
         elog(FATAL, "CleanupTransaction: unexpected state %s",
              TransStateAsString(s->state));

+    if (accessedTempRel != NULL)
+    {
+        CleanupAccessedTempRel();
+
+        hash_destroy(accessedTempRel);
+        accessedTempRel = NULL;
+    }
+
     /*
      * do abort cleanup processing
      */
Index: src/include/access/xact.h
===================================================================
RCS file: /root/cvsrepo/pgsql/src/include/access/xact.h,v
retrieving revision 1.95
diff -u -r1.95 xact.h
--- src/include/access/xact.h    11 Aug 2008 11:05:11 -0000    1.95
+++ src/include/access/xact.h    9 Oct 2008 21:44:04 -0000
@@ -18,6 +18,7 @@
 #include "nodes/pg_list.h"
 #include "storage/relfilenode.h"
 #include "utils/timestamp.h"
+#include "postgres_ext.h"


 /*
@@ -44,8 +45,10 @@
 /* Asynchronous commits */
 extern bool XactSyncCommit;

-/* Kluge for 2PC support */
-extern bool MyXactAccessedTempRel;
+/* List of temp tables accessed during a transaction for 2PC support */
+extern void enlistRelationIdFor2PCChecks(Oid relationId);
+/* Check if a temp table has been prepared for 2PC but not committed yet */
+extern bool isPreparedTempRelation(Oid relationId);

 /*
  *    start- and end-of-transaction callbacks for dynamically loaded modules
Index: src/backend/catalog/dependency.c
===================================================================
RCS file: /root/cvsrepo/pgsql/src/backend/catalog/dependency.c,v
retrieving revision 1.81
diff -u -r1.81 dependency.c
--- src/backend/catalog/dependency.c    4 Oct 2008 21:56:52 -0000    1.81
+++ src/backend/catalog/dependency.c    9 Oct 2008 21:44:04 -0000
@@ -677,6 +677,12 @@
         otherObject.objectId = foundDep->objid;
         otherObject.objectSubId = foundDep->objsubid;

+        if (isPreparedTempRelation(foundDep->objid))
+        {
+            elog(DEBUG3, "temp relation %d is already prepared, ignoring", foundDep->objid);
+            continue;
+        }
+
         /*
          * Must lock the dependent object before recursing to it.
          */

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Greg Smith
Дата:
Сообщение: Re: How is random_page_cost=4 ok?
Следующее
От: Grzegorz Jaskiewicz
Дата:
Сообщение: Re: patch: Allow the UUID type to accept non-standard formats