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: [EMAIL PROTECTED]
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_rollback 2pc_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 
are not 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.
                 */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to