You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hawq.apache.org by iw...@apache.org on 2016/08/30 01:48:27 UTC

incubator-hawq git commit: HAWQ-1015. Add feature test for transactions with new test framework

Repository: incubator-hawq
Updated Branches:
  refs/heads/master 27022e561 -> cb80c3331


HAWQ-1015. Add feature test for transactions with new test framework


Project: http://git-wip-us.apache.org/repos/asf/incubator-hawq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-hawq/commit/cb80c333
Tree: http://git-wip-us.apache.org/repos/asf/incubator-hawq/tree/cb80c333
Diff: http://git-wip-us.apache.org/repos/asf/incubator-hawq/diff/cb80c333

Branch: refs/heads/master
Commit: cb80c333176e38a29eba618b70440b12f1b4ab33
Parents: 27022e5
Author: ivan <iw...@pivotal.io>
Authored: Mon Aug 29 11:01:31 2016 +0800
Committer: ivan <iw...@pivotal.io>
Committed: Tue Aug 30 09:46:28 2016 +0800

----------------------------------------------------------------------
 .../feature/transactions/ans/transactions.ans   | 558 +++++++++++++++++++
 .../feature/transactions/sql/transactions.sql   | 342 ++++++++++++
 .../feature/transactions/test_transactions.cpp  |  19 +
 3 files changed, 919 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/cb80c333/src/test/feature/transactions/ans/transactions.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/transactions/ans/transactions.ans b/src/test/feature/transactions/ans/transactions.ans
new file mode 100755
index 0000000..35669f4
--- /dev/null
+++ b/src/test/feature/transactions/ans/transactions.ans
@@ -0,0 +1,558 @@
+--
+-- TRANSACTIONS
+--
+CREATE TABLE aggtest (
+    a           int2,
+    b           float4
+);
+CREATE TABLE
+INSERT INTO aggtest VALUES (56, 7.8), (100, 99.097), (0, 0.09561), (42, 324.78);
+INSERT 0 4
+BEGIN;
+BEGIN
+SELECT * 
+   INTO TABLE xacttest
+   FROM aggtest;
+SELECT 4
+INSERT INTO xacttest (a, b) VALUES (777, 777.777);
+INSERT 0 1
+END;
+COMMIT
+-- should retrieve one value--
+SELECT a FROM xacttest WHERE a > 100;
+  a  
+-----
+ 777
+(1 row)
+
+BEGIN;
+BEGIN
+CREATE TABLE disappear (a int4);
+CREATE TABLE
+TRUNCATE aggtest;
+TRUNCATE TABLE
+-- should be empty
+SELECT * FROM aggtest;
+ a | b 
+---+---
+(0 rows)
+
+ABORT;
+ROLLBACK
+-- should not exist 
+SELECT oid FROM pg_class WHERE relname = 'disappear';
+ oid 
+-----
+(0 rows)
+
+-- should have members again 
+SELECT * FROM aggtest;
+  a  |    b    
+-----+---------
+  56 |     7.8
+ 100 |  99.097
+   0 | 0.09561
+  42 |  324.78
+(4 rows)
+
+drop table aggtest;
+DROP TABLE
+-- Read-only tests
+CREATE TABLE writetest (a int);
+CREATE TABLE
+CREATE TEMPORARY TABLE temptest (a int);
+CREATE TABLE
+SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY;
+SET
+DROP TABLE writetest; -- fail
+psql:/tmp/TestTransaction_BasicTest.sql:56: ERROR:  transaction is read-only
+INSERT INTO writetest VALUES (1); -- fail
+psql:/tmp/TestTransaction_BasicTest.sql:57: ERROR:  transaction is read-only
+SELECT * FROM writetest; -- ok
+ a 
+---
+(0 rows)
+
+-- DELETE FROM temptest; -- ok
+-- UPDATE temptest SET a = 0 FROM writetest WHERE temptest.a = 1 AND writetest.a = temptest.a; -- ok
+-- PREPARE test AS INSERT INTO writetest VALUES (1); -- ok
+-- EXECUTE test; -- fail
+SELECT * FROM writetest, temptest; -- ok
+ a | a 
+---+---
+(0 rows)
+
+CREATE TABLE test AS SELECT * FROM writetest; -- fail
+psql:/tmp/TestTransaction_BasicTest.sql:64: ERROR:  transaction is read-only
+START TRANSACTION READ WRITE;
+START TRANSACTION
+DROP TABLE writetest; -- ok
+DROP TABLE
+COMMIT;
+COMMIT
+-- Subtransactions, basic tests
+-- create & drop tables
+SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE;
+SET
+CREATE TABLE foobar (a int);
+CREATE TABLE
+BEGIN;
+BEGIN
+	CREATE TABLE foo (a int);
+CREATE TABLE
+	SAVEPOINT one;
+SAVEPOINT
+		DROP TABLE foo;
+DROP TABLE
+		CREATE TABLE bar (a int);
+CREATE TABLE
+	ROLLBACK TO SAVEPOINT one;
+ROLLBACK
+	RELEASE SAVEPOINT one;
+RELEASE
+	SAVEPOINT two;
+SAVEPOINT
+		CREATE TABLE baz (a int);
+CREATE TABLE
+	RELEASE SAVEPOINT two;
+RELEASE
+	drop TABLE foobar;
+DROP TABLE
+	CREATE TABLE barbaz (a int);
+CREATE TABLE
+COMMIT;
+COMMIT
+-- should exist: barbaz, baz, foo
+SELECT * FROM foo;		-- should be empty
+ a 
+---
+(0 rows)
+
+SELECT * FROM bar;		-- shouldn't exist
+psql:/tmp/TestTransaction_BasicTest.sql:89: ERROR:  relation "bar" does not exist
+LINE 1: SELECT * FROM bar;
+                      ^
+SELECT * FROM barbaz;	-- should be empty
+ a 
+---
+(0 rows)
+
+SELECT * FROM baz;		-- should be empty
+ a 
+---
+(0 rows)
+
+-- inserts
+BEGIN;
+BEGIN
+	INSERT INTO foo VALUES (1);
+INSERT 0 1
+	SAVEPOINT one;
+SAVEPOINT
+		INSERT into bar VALUES (1);
+psql:/tmp/TestTransaction_BasicTest.sql:97: ERROR:  relation "bar" does not exist
+	ROLLBACK TO one;
+ROLLBACK
+	RELEASE SAVEPOINT one;
+RELEASE
+	SAVEPOINT two;
+SAVEPOINT
+		INSERT into barbaz VALUES (1);
+INSERT 0 1
+	RELEASE two;
+RELEASE
+	SAVEPOINT three;
+SAVEPOINT
+		SAVEPOINT four;
+SAVEPOINT
+			INSERT INTO foo VALUES (2);
+INSERT 0 1
+		RELEASE SAVEPOINT four;
+RELEASE
+	ROLLBACK TO SAVEPOINT three;
+ROLLBACK
+	RELEASE SAVEPOINT three;
+RELEASE
+	INSERT INTO foo VALUES (3);
+INSERT 0 1
+COMMIT;
+COMMIT
+SELECT * FROM foo;		-- should have 1 and 3
+ a 
+---
+ 1
+ 3
+(2 rows)
+
+SELECT * FROM barbaz;	-- should have 1
+ a 
+---
+ 1
+(1 row)
+
+-- test whole-tree commit
+BEGIN;
+BEGIN
+	SAVEPOINT one;
+SAVEPOINT
+		SELECT foo;
+psql:/tmp/TestTransaction_BasicTest.sql:117: ERROR:  column "foo" does not exist
+LINE 1: SELECT foo;
+               ^
+	ROLLBACK TO SAVEPOINT one;
+ROLLBACK
+	RELEASE SAVEPOINT one;
+RELEASE
+	SAVEPOINT two;
+SAVEPOINT
+		CREATE TABLE savepoints (a int);
+CREATE TABLE
+		SAVEPOINT three;
+SAVEPOINT
+			INSERT INTO savepoints VALUES (1);
+INSERT 0 1
+			SAVEPOINT four;
+SAVEPOINT
+				INSERT INTO savepoints VALUES (2);
+INSERT 0 1
+				SAVEPOINT five;
+SAVEPOINT
+					INSERT INTO savepoints VALUES (3);
+INSERT 0 1
+				ROLLBACK TO SAVEPOINT five;
+ROLLBACK
+COMMIT;
+COMMIT
+COMMIT;		-- should not be in a transaction block
+psql:/tmp/TestTransaction_BasicTest.sql:130: WARNING:  there is no transaction in progress
+COMMIT
+SELECT * FROM savepoints;
+ a 
+---
+ 1
+ 2
+(2 rows)
+
+-- test whole-tree rollback
+BEGIN;
+BEGIN
+	SAVEPOINT one;
+SAVEPOINT
+		INSERT INTO savepoints VALUES (23);
+INSERT 0 1
+	RELEASE SAVEPOINT one;
+RELEASE
+	SAVEPOINT two;
+SAVEPOINT
+		INSERT INTO savepoints VALUES (24);
+INSERT 0 1
+		SAVEPOINT three;
+SAVEPOINT
+			INSERT INTO savepoints VALUES (25);
+INSERT 0 1
+ROLLBACK;
+ROLLBACK
+COMMIT;		-- should not be in a transaction block
+psql:/tmp/TestTransaction_BasicTest.sql:143: WARNING:  there is no transaction in progress
+COMMIT
+		
+SELECT * FROM savepoints ORDER BY 1;
+ a 
+---
+ 1
+ 2
+(2 rows)
+
+-- test whole-tree commit on an aborted subtransaction
+BEGIN;
+BEGIN
+	INSERT INTO savepoints VALUES (4);
+INSERT 0 1
+	SAVEPOINT one;
+SAVEPOINT
+		INSERT INTO savepoints VALUES (5);
+INSERT 0 1
+		SELECT foo;
+psql:/tmp/TestTransaction_BasicTest.sql:152: ERROR:  column "foo" does not exist
+LINE 1: SELECT foo;
+               ^
+COMMIT;
+ROLLBACK
+SELECT * FROM savepoints ORDER BY 1;
+ a 
+---
+ 1
+ 2
+(2 rows)
+
+BEGIN;
+BEGIN
+	INSERT INTO savepoints VALUES (6);
+INSERT 0 1
+	SAVEPOINT one;
+SAVEPOINT
+		INSERT INTO savepoints VALUES (7);
+INSERT 0 1
+	RELEASE SAVEPOINT one;
+RELEASE
+	INSERT INTO savepoints VALUES (8);
+INSERT 0 1
+COMMIT;
+COMMIT
+-- rows 6 and 8 should have been created by the same xact
+-- SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=6 AND b.a=8;
+-- rows 6 and 7 should have been created by different xacts
+-- SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=6 AND b.a=7;
+BEGIN;
+BEGIN
+	INSERT INTO savepoints VALUES (9);
+INSERT 0 1
+	SAVEPOINT one;
+SAVEPOINT
+		INSERT INTO savepoints VALUES (10);
+INSERT 0 1
+	ROLLBACK TO SAVEPOINT one;
+ROLLBACK
+		INSERT INTO savepoints VALUES (11);
+INSERT 0 1
+COMMIT;
+COMMIT
+SELECT a FROM savepoints WHERE a in (9, 10, 11) ORDER BY 1;
+ a  
+----
+  9
+ 11
+(2 rows)
+
+-- rows 9 and 11 should have been created by different xacts
+-- SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=9 AND b.a=11;
+BEGIN;
+BEGIN
+	INSERT INTO savepoints VALUES (12);
+INSERT 0 1
+	SAVEPOINT one;
+SAVEPOINT
+		INSERT INTO savepoints VALUES (13);
+INSERT 0 1
+		SAVEPOINT two;
+SAVEPOINT
+			INSERT INTO savepoints VALUES (14);
+INSERT 0 1
+	ROLLBACK TO SAVEPOINT one;
+ROLLBACK
+		INSERT INTO savepoints VALUES (15);
+INSERT 0 1
+		SAVEPOINT two;
+SAVEPOINT
+			INSERT INTO savepoints VALUES (16);
+INSERT 0 1
+			SAVEPOINT three;
+SAVEPOINT
+				INSERT INTO savepoints VALUES (17);
+INSERT 0 1
+COMMIT;
+COMMIT
+SELECT a FROM savepoints WHERE a BETWEEN 12 AND 17 ORDER BY 1;
+ a  
+----
+ 12
+ 15
+ 16
+ 17
+(4 rows)
+
+BEGIN;
+BEGIN
+	INSERT INTO savepoints VALUES (18);
+INSERT 0 1
+	SAVEPOINT one;
+SAVEPOINT
+		INSERT INTO savepoints VALUES (19);
+INSERT 0 1
+		SAVEPOINT two;
+SAVEPOINT
+			INSERT INTO savepoints VALUES (20);
+INSERT 0 1
+	ROLLBACK TO SAVEPOINT one;
+ROLLBACK
+		INSERT INTO savepoints VALUES (21);
+INSERT 0 1
+	ROLLBACK TO SAVEPOINT one;
+ROLLBACK
+		INSERT INTO savepoints VALUES (22);
+INSERT 0 1
+COMMIT;
+COMMIT
+SELECT a FROM savepoints WHERE a BETWEEN 18 AND 22 ORDER BY 1;
+ a  
+----
+ 18
+ 22
+(2 rows)
+
+DROP TABLE savepoints;
+DROP TABLE
+-- only in a transaction block:
+SAVEPOINT one;
+psql:/tmp/TestTransaction_BasicTest.sql:210: ERROR:  SAVEPOINT may only be used in transaction blocks
+ROLLBACK TO SAVEPOINT one;
+psql:/tmp/TestTransaction_BasicTest.sql:211: ERROR:  ROLLBACK TO SAVEPOINT may only be used in transaction blocks
+RELEASE SAVEPOINT one;
+psql:/tmp/TestTransaction_BasicTest.sql:212: ERROR:  RELEASE SAVEPOINT may only be used in transaction blocks
+-- Only "rollback to" allowed in aborted state
+BEGIN;
+BEGIN
+  SAVEPOINT one;
+SAVEPOINT
+  SELECT 0/0;
+psql:/tmp/TestTransaction_BasicTest.sql:217: ERROR:  division by zero
+  SAVEPOINT two;    -- ignored till the end of ...
+psql:/tmp/TestTransaction_BasicTest.sql:218: ERROR:  current transaction is aborted, commands ignored until end of transaction block
+  RELEASE SAVEPOINT one;      -- ignored till the end of ...
+psql:/tmp/TestTransaction_BasicTest.sql:219: ERROR:  current transaction is aborted, commands ignored until end of transaction block
+  ROLLBACK TO SAVEPOINT one;
+ROLLBACK
+  SELECT 1;
+ ?column? 
+----------
+        1
+(1 row)
+
+COMMIT;
+COMMIT
+SELECT 1;			-- this should work
+ ?column? 
+----------
+        1
+(1 row)
+
+-- check non-transactional behavior of cursors
+-- BEGIN;
+-- 	DECLARE c CURSOR FOR SELECT unique2 FROM tenk1 ORDER BY 1;
+-- 	SAVEPOINT one;
+-- 		FETCH 10 FROM c;
+-- 	ROLLBACK TO SAVEPOINT one;
+-- 		FETCH 10 FROM c;
+-- 	RELEASE SAVEPOINT one;
+-- 	FETCH 10 FROM c;
+-- 	CLOSE c;
+-- 	DECLARE c CURSOR FOR SELECT unique2/0 FROM tenk1 ORDER BY 1;
+-- 	SAVEPOINT two;
+-- 		FETCH 10 FROM c;
+-- 	ROLLBACK TO SAVEPOINT two;
+-- 	-- c is now dead to the world ...
+-- 		FETCH 10 FROM c;
+-- 	ROLLBACK TO SAVEPOINT two;
+-- 	RELEASE SAVEPOINT two;
+-- 	FETCH 10 FROM c;
+-- COMMIT;
+--
+-- Check that "stable" functions are really stable.  They should not be
+-- able to see the partial results of the calling query.  (Ideally we would
+-- also check that they don't see commits of concurrent transactions, but
+-- that's a mite hard to do within the limitations of pg_regress.)
+--
+select * from xacttest;
+  a  |    b    
+-----+---------
+  56 |     7.8
+ 100 |  99.097
+   0 | 0.09561
+  42 |  324.78
+ 777 | 777.777
+(5 rows)
+
+-- create or replace function max_xacttest() returns smallint language sql as
+-- 'select max(a) from xacttest' stable;
+-- begin;
+-- update xacttest set a = max_xacttest() + 10 where a > 0;
+-- select * from xacttest;
+-- rollback;
+-- But a volatile function can see the partial results of the calling query
+-- create or replace function max_xacttest() returns smallint language sql as
+-- 'select max(a) from xacttest' volatile;
+-- begin;
+-- update xacttest set a = max_xacttest() + 10 where a > 0;
+-- select * from xacttest;
+-- rollback;
+-- Now the same test with plpgsql (since it depends on SPI which is different)
+-- create or replace function max_xacttest() returns smallint language plpgsql as
+-- 'begin return max(a) from xacttest; end' stable;
+-- begin;
+-- update xacttest set a = max_xacttest() + 10 where a > 0;
+-- select * from xacttest;
+-- rollback;
+-- create or replace function max_xacttest() returns smallint language plpgsql as
+-- 'begin return max(a) from xacttest; end' volatile;
+-- begin;
+-- update xacttest set a = max_xacttest() + 10 where a > 0;
+-- select * from xacttest;
+-- rollback;
+-- test case for problems with dropping an open relation during abort
+-- BEGIN;
+-- 	savepoint x;
+-- 		CREATE TABLE koju (a INT UNIQUE);
+-- 		INSERT INTO koju VALUES (1);
+-- 		INSERT INTO koju VALUES (1);
+-- 	rollback to x;
+-- 	CREATE TABLE koju (a INT UNIQUE);
+-- 	INSERT INTO koju VALUES (1);
+-- 	INSERT INTO koju VALUES (1);
+-- ROLLBACK;
+DROP TABLE foo;
+DROP TABLE
+DROP TABLE baz;
+DROP TABLE
+DROP TABLE barbaz;
+DROP TABLE
+-- verify that cursors created during an aborted subtransaction are
+-- closed, but that we do not rollback the effect of any FETCHs
+-- performed in the aborted subtransaction
+-- begin;
+-- savepoint x;
+-- create table abc (a int);
+-- insert into abc values (5);
+-- insert into abc values (10);
+-- declare foo cursor for select * from abc;
+-- fetch from foo;
+-- rollback to x;
+-- should fail
+-- fetch from foo;
+-- commit;
+-- begin;
+-- create table abc (a int);
+-- insert into abc values (5);
+-- insert into abc values (10);
+-- insert into abc values (15);
+-- declare foo cursor for select * from abc;
+-- fetch from foo;
+-- savepoint x;
+-- fetch from foo;
+-- rollback to x;
+-- fetch from foo;
+-- abort;
+-- tests for the "tid" type
+SELECT '(3, 3)'::tid = '(3, 4)'::tid;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT '(3, 3)'::tid = '(3, 3)'::tid;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT '(3, 3)'::tid <> '(3, 3)'::tid;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT '(3, 3)'::tid <> '(3, 4)'::tid;
+ ?column? 
+----------
+ t
+(1 row)
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/cb80c333/src/test/feature/transactions/sql/transactions.sql
----------------------------------------------------------------------
diff --git a/src/test/feature/transactions/sql/transactions.sql b/src/test/feature/transactions/sql/transactions.sql
new file mode 100644
index 0000000..45ded0d
--- /dev/null
+++ b/src/test/feature/transactions/sql/transactions.sql
@@ -0,0 +1,342 @@
+--
+-- TRANSACTIONS
+--
+
+CREATE TABLE aggtest (
+    a           int2,
+    b           float4
+);
+
+INSERT INTO aggtest VALUES (56, 7.8), (100, 99.097), (0, 0.09561), (42, 324.78);
+
+BEGIN;
+
+SELECT * 
+   INTO TABLE xacttest
+   FROM aggtest;
+
+INSERT INTO xacttest (a, b) VALUES (777, 777.777);
+
+END;
+
+-- should retrieve one value--
+SELECT a FROM xacttest WHERE a > 100;
+
+
+BEGIN;
+
+CREATE TABLE disappear (a int4);
+
+TRUNCATE aggtest;
+
+-- should be empty
+SELECT * FROM aggtest;
+
+ABORT;
+
+-- should not exist 
+SELECT oid FROM pg_class WHERE relname = 'disappear';
+
+-- should have members again 
+SELECT * FROM aggtest;
+
+drop table aggtest;
+
+
+-- Read-only tests
+
+CREATE TABLE writetest (a int);
+CREATE TEMPORARY TABLE temptest (a int);
+
+SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY;
+
+DROP TABLE writetest; -- fail
+INSERT INTO writetest VALUES (1); -- fail
+SELECT * FROM writetest; -- ok
+-- DELETE FROM temptest; -- ok
+-- UPDATE temptest SET a = 0 FROM writetest WHERE temptest.a = 1 AND writetest.a = temptest.a; -- ok
+-- PREPARE test AS INSERT INTO writetest VALUES (1); -- ok
+-- EXECUTE test; -- fail
+SELECT * FROM writetest, temptest; -- ok
+CREATE TABLE test AS SELECT * FROM writetest; -- fail
+
+START TRANSACTION READ WRITE;
+DROP TABLE writetest; -- ok
+COMMIT;
+
+-- Subtransactions, basic tests
+-- create & drop tables
+SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE;
+CREATE TABLE foobar (a int);
+BEGIN;
+	CREATE TABLE foo (a int);
+	SAVEPOINT one;
+		DROP TABLE foo;
+		CREATE TABLE bar (a int);
+	ROLLBACK TO SAVEPOINT one;
+	RELEASE SAVEPOINT one;
+	SAVEPOINT two;
+		CREATE TABLE baz (a int);
+	RELEASE SAVEPOINT two;
+	drop TABLE foobar;
+	CREATE TABLE barbaz (a int);
+COMMIT;
+-- should exist: barbaz, baz, foo
+SELECT * FROM foo;		-- should be empty
+SELECT * FROM bar;		-- shouldn't exist
+SELECT * FROM barbaz;	-- should be empty
+SELECT * FROM baz;		-- should be empty
+
+-- inserts
+BEGIN;
+	INSERT INTO foo VALUES (1);
+	SAVEPOINT one;
+		INSERT into bar VALUES (1);
+	ROLLBACK TO one;
+	RELEASE SAVEPOINT one;
+	SAVEPOINT two;
+		INSERT into barbaz VALUES (1);
+	RELEASE two;
+	SAVEPOINT three;
+		SAVEPOINT four;
+			INSERT INTO foo VALUES (2);
+		RELEASE SAVEPOINT four;
+	ROLLBACK TO SAVEPOINT three;
+	RELEASE SAVEPOINT three;
+	INSERT INTO foo VALUES (3);
+COMMIT;
+SELECT * FROM foo;		-- should have 1 and 3
+SELECT * FROM barbaz;	-- should have 1
+
+-- test whole-tree commit
+BEGIN;
+	SAVEPOINT one;
+		SELECT foo;
+	ROLLBACK TO SAVEPOINT one;
+	RELEASE SAVEPOINT one;
+	SAVEPOINT two;
+		CREATE TABLE savepoints (a int);
+		SAVEPOINT three;
+			INSERT INTO savepoints VALUES (1);
+			SAVEPOINT four;
+				INSERT INTO savepoints VALUES (2);
+				SAVEPOINT five;
+					INSERT INTO savepoints VALUES (3);
+				ROLLBACK TO SAVEPOINT five;
+COMMIT;
+COMMIT;		-- should not be in a transaction block
+SELECT * FROM savepoints;
+
+-- test whole-tree rollback
+BEGIN;
+	SAVEPOINT one;
+		INSERT INTO savepoints VALUES (23);
+	RELEASE SAVEPOINT one;
+	SAVEPOINT two;
+		INSERT INTO savepoints VALUES (24);
+		SAVEPOINT three;
+			INSERT INTO savepoints VALUES (25);
+ROLLBACK;
+COMMIT;		-- should not be in a transaction block
+		
+SELECT * FROM savepoints ORDER BY 1;
+
+-- test whole-tree commit on an aborted subtransaction
+BEGIN;
+	INSERT INTO savepoints VALUES (4);
+	SAVEPOINT one;
+		INSERT INTO savepoints VALUES (5);
+		SELECT foo;
+COMMIT;
+SELECT * FROM savepoints ORDER BY 1;
+
+BEGIN;
+	INSERT INTO savepoints VALUES (6);
+	SAVEPOINT one;
+		INSERT INTO savepoints VALUES (7);
+	RELEASE SAVEPOINT one;
+	INSERT INTO savepoints VALUES (8);
+COMMIT;
+-- rows 6 and 8 should have been created by the same xact
+-- SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=6 AND b.a=8;
+-- rows 6 and 7 should have been created by different xacts
+-- SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=6 AND b.a=7;
+
+BEGIN;
+	INSERT INTO savepoints VALUES (9);
+	SAVEPOINT one;
+		INSERT INTO savepoints VALUES (10);
+	ROLLBACK TO SAVEPOINT one;
+		INSERT INTO savepoints VALUES (11);
+COMMIT;
+SELECT a FROM savepoints WHERE a in (9, 10, 11) ORDER BY 1;
+-- rows 9 and 11 should have been created by different xacts
+-- SELECT a.xmin = b.xmin FROM savepoints a, savepoints b WHERE a.a=9 AND b.a=11;
+
+BEGIN;
+	INSERT INTO savepoints VALUES (12);
+	SAVEPOINT one;
+		INSERT INTO savepoints VALUES (13);
+		SAVEPOINT two;
+			INSERT INTO savepoints VALUES (14);
+	ROLLBACK TO SAVEPOINT one;
+		INSERT INTO savepoints VALUES (15);
+		SAVEPOINT two;
+			INSERT INTO savepoints VALUES (16);
+			SAVEPOINT three;
+				INSERT INTO savepoints VALUES (17);
+COMMIT;
+SELECT a FROM savepoints WHERE a BETWEEN 12 AND 17 ORDER BY 1;
+
+BEGIN;
+	INSERT INTO savepoints VALUES (18);
+	SAVEPOINT one;
+		INSERT INTO savepoints VALUES (19);
+		SAVEPOINT two;
+			INSERT INTO savepoints VALUES (20);
+	ROLLBACK TO SAVEPOINT one;
+		INSERT INTO savepoints VALUES (21);
+	ROLLBACK TO SAVEPOINT one;
+		INSERT INTO savepoints VALUES (22);
+COMMIT;
+SELECT a FROM savepoints WHERE a BETWEEN 18 AND 22 ORDER BY 1;
+
+DROP TABLE savepoints;
+
+-- only in a transaction block:
+SAVEPOINT one;
+ROLLBACK TO SAVEPOINT one;
+RELEASE SAVEPOINT one;
+
+-- Only "rollback to" allowed in aborted state
+BEGIN;
+  SAVEPOINT one;
+  SELECT 0/0;
+  SAVEPOINT two;    -- ignored till the end of ...
+  RELEASE SAVEPOINT one;      -- ignored till the end of ...
+  ROLLBACK TO SAVEPOINT one;
+  SELECT 1;
+COMMIT;
+SELECT 1;			-- this should work
+
+-- check non-transactional behavior of cursors
+-- BEGIN;
+-- 	DECLARE c CURSOR FOR SELECT unique2 FROM tenk1 ORDER BY 1;
+-- 	SAVEPOINT one;
+-- 		FETCH 10 FROM c;
+-- 	ROLLBACK TO SAVEPOINT one;
+-- 		FETCH 10 FROM c;
+-- 	RELEASE SAVEPOINT one;
+-- 	FETCH 10 FROM c;
+-- 	CLOSE c;
+-- 	DECLARE c CURSOR FOR SELECT unique2/0 FROM tenk1 ORDER BY 1;
+-- 	SAVEPOINT two;
+-- 		FETCH 10 FROM c;
+-- 	ROLLBACK TO SAVEPOINT two;
+-- 	-- c is now dead to the world ...
+-- 		FETCH 10 FROM c;
+-- 	ROLLBACK TO SAVEPOINT two;
+-- 	RELEASE SAVEPOINT two;
+-- 	FETCH 10 FROM c;
+-- COMMIT;
+
+--
+-- Check that "stable" functions are really stable.  They should not be
+-- able to see the partial results of the calling query.  (Ideally we would
+-- also check that they don't see commits of concurrent transactions, but
+-- that's a mite hard to do within the limitations of pg_regress.)
+--
+select * from xacttest;
+
+-- create or replace function max_xacttest() returns smallint language sql as
+-- 'select max(a) from xacttest' stable;
+
+-- begin;
+-- update xacttest set a = max_xacttest() + 10 where a > 0;
+-- select * from xacttest;
+-- rollback;
+
+-- But a volatile function can see the partial results of the calling query
+-- create or replace function max_xacttest() returns smallint language sql as
+-- 'select max(a) from xacttest' volatile;
+
+-- begin;
+-- update xacttest set a = max_xacttest() + 10 where a > 0;
+-- select * from xacttest;
+-- rollback;
+
+-- Now the same test with plpgsql (since it depends on SPI which is different)
+-- create or replace function max_xacttest() returns smallint language plpgsql as
+-- 'begin return max(a) from xacttest; end' stable;
+
+-- begin;
+-- update xacttest set a = max_xacttest() + 10 where a > 0;
+-- select * from xacttest;
+-- rollback;
+
+-- create or replace function max_xacttest() returns smallint language plpgsql as
+-- 'begin return max(a) from xacttest; end' volatile;
+
+-- begin;
+-- update xacttest set a = max_xacttest() + 10 where a > 0;
+-- select * from xacttest;
+-- rollback;
+
+
+-- test case for problems with dropping an open relation during abort
+-- BEGIN;
+-- 	savepoint x;
+-- 		CREATE TABLE koju (a INT UNIQUE);
+-- 		INSERT INTO koju VALUES (1);
+-- 		INSERT INTO koju VALUES (1);
+-- 	rollback to x;
+
+-- 	CREATE TABLE koju (a INT UNIQUE);
+-- 	INSERT INTO koju VALUES (1);
+-- 	INSERT INTO koju VALUES (1);
+-- ROLLBACK;
+
+DROP TABLE foo;
+DROP TABLE baz;
+DROP TABLE barbaz;
+
+-- verify that cursors created during an aborted subtransaction are
+-- closed, but that we do not rollback the effect of any FETCHs
+-- performed in the aborted subtransaction
+-- begin;
+
+-- savepoint x;
+-- create table abc (a int);
+-- insert into abc values (5);
+-- insert into abc values (10);
+-- declare foo cursor for select * from abc;
+-- fetch from foo;
+-- rollback to x;
+
+-- should fail
+-- fetch from foo;
+-- commit;
+
+-- begin;
+
+-- create table abc (a int);
+-- insert into abc values (5);
+-- insert into abc values (10);
+-- insert into abc values (15);
+-- declare foo cursor for select * from abc;
+
+-- fetch from foo;
+
+-- savepoint x;
+-- fetch from foo;
+-- rollback to x;
+
+-- fetch from foo;
+
+-- abort;
+
+-- tests for the "tid" type
+SELECT '(3, 3)'::tid = '(3, 4)'::tid;
+SELECT '(3, 3)'::tid = '(3, 3)'::tid;
+SELECT '(3, 3)'::tid <> '(3, 3)'::tid;
+SELECT '(3, 3)'::tid <> '(3, 4)'::tid;

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/cb80c333/src/test/feature/transactions/test_transactions.cpp
----------------------------------------------------------------------
diff --git a/src/test/feature/transactions/test_transactions.cpp b/src/test/feature/transactions/test_transactions.cpp
new file mode 100644
index 0000000..c3254da
--- /dev/null
+++ b/src/test/feature/transactions/test_transactions.cpp
@@ -0,0 +1,19 @@
+#include "gtest/gtest.h"
+
+#include "lib/sql_util.h"
+
+using std::string;
+
+class TestTransaction: public ::testing::Test
+{
+	public:
+		TestTransaction() { }
+		~TestTransaction() {}
+};
+
+TEST_F(TestTransaction, BasicTest)
+{
+	hawq::test::SQLUtility util;
+	util.execSQLFile("transactions/sql/transactions.sql",
+	                 "transactions/ans/transactions.ans");
+}