summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2017-03-20 16:30:08 +0000
committerTom Lane2017-03-20 16:30:23 +0000
commitbe6c3d19fd454359f05176eb1add82d4fc6e7758 (patch)
tree201685e8fabfcc20e55140cb66ec84cfdbd0aa35
parent9cf6033281fdaf938b826545a643f951086d8671 (diff)
Improve regression test coverage for TID scanning.
TidScan plan nodes were not systematically tested before. These additions raise the LOC coverage number for the basic regression tests from 52% to 92% in nodeTidscan.c, and from 60% to 93% in tidpath.c. Andres Freund, tweaked a bit by me Discussion: https://postgr.es/m/20170320062511.hp5qeurtxrwsvfxr@alap3.anarazel.de
-rw-r--r--src/test/regress/expected/tidscan.out179
-rw-r--r--src/test/regress/parallel_schedule2
-rw-r--r--src/test/regress/serial_schedule1
-rw-r--r--src/test/regress/sql/tidscan.sql66
4 files changed, 247 insertions, 1 deletions
diff --git a/src/test/regress/expected/tidscan.out b/src/test/regress/expected/tidscan.out
new file mode 100644
index 0000000000..521ed1b2f9
--- /dev/null
+++ b/src/test/regress/expected/tidscan.out
@@ -0,0 +1,179 @@
+-- tests for tidscans
+CREATE TABLE tidscan(id integer);
+-- only insert a few rows, we don't want to spill onto a second table page
+INSERT INTO tidscan VALUES (1), (2), (3);
+-- show ctids
+SELECT ctid, * FROM tidscan;
+ ctid | id
+-------+----
+ (0,1) | 1
+ (0,2) | 2
+ (0,3) | 3
+(3 rows)
+
+-- ctid equality - implemented as tidscan
+EXPLAIN (COSTS OFF)
+SELECT ctid, * FROM tidscan WHERE ctid = '(0,1)';
+ QUERY PLAN
+-----------------------------------
+ Tid Scan on tidscan
+ TID Cond: (ctid = '(0,1)'::tid)
+(2 rows)
+
+SELECT ctid, * FROM tidscan WHERE ctid = '(0,1)';
+ ctid | id
+-------+----
+ (0,1) | 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT ctid, * FROM tidscan WHERE '(0,1)' = ctid;
+ QUERY PLAN
+-----------------------------------
+ Tid Scan on tidscan
+ TID Cond: ('(0,1)'::tid = ctid)
+(2 rows)
+
+SELECT ctid, * FROM tidscan WHERE '(0,1)' = ctid;
+ ctid | id
+-------+----
+ (0,1) | 1
+(1 row)
+
+-- ctid = ScalarArrayOp - implemented as tidscan
+EXPLAIN (COSTS OFF)
+SELECT ctid, * FROM tidscan WHERE ctid = ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
+ QUERY PLAN
+-------------------------------------------------------
+ Tid Scan on tidscan
+ TID Cond: (ctid = ANY ('{"(0,1)","(0,2)"}'::tid[]))
+(2 rows)
+
+SELECT ctid, * FROM tidscan WHERE ctid = ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
+ ctid | id
+-------+----
+ (0,1) | 1
+ (0,2) | 2
+(2 rows)
+
+-- ctid != ScalarArrayOp - can't be implemented as tidscan
+EXPLAIN (COSTS OFF)
+SELECT ctid, * FROM tidscan WHERE ctid != ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
+ QUERY PLAN
+------------------------------------------------------
+ Seq Scan on tidscan
+ Filter: (ctid <> ANY ('{"(0,1)","(0,2)"}'::tid[]))
+(2 rows)
+
+SELECT ctid, * FROM tidscan WHERE ctid != ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
+ ctid | id
+-------+----
+ (0,1) | 1
+ (0,2) | 2
+ (0,3) | 3
+(3 rows)
+
+-- tid equality extracted from sub-AND clauses
+EXPLAIN (COSTS OFF)
+SELECT ctid, * FROM tidscan
+WHERE (id = 3 AND ctid IN ('(0,2)', '(0,3)')) OR (ctid = '(0,1)' AND id = 1);
+ QUERY PLAN
+--------------------------------------------------------------------------------------------------------------
+ Tid Scan on tidscan
+ TID Cond: ((ctid = ANY ('{"(0,2)","(0,3)"}'::tid[])) OR (ctid = '(0,1)'::tid))
+ Filter: (((id = 3) AND (ctid = ANY ('{"(0,2)","(0,3)"}'::tid[]))) OR ((ctid = '(0,1)'::tid) AND (id = 1)))
+(3 rows)
+
+SELECT ctid, * FROM tidscan
+WHERE (id = 3 AND ctid IN ('(0,2)', '(0,3)')) OR (ctid = '(0,1)' AND id = 1);
+ ctid | id
+-------+----
+ (0,1) | 1
+ (0,3) | 3
+(2 rows)
+
+-- exercise backward scan and rewind
+BEGIN;
+DECLARE c CURSOR FOR
+SELECT ctid, * FROM tidscan WHERE ctid = ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
+FETCH ALL FROM c;
+ ctid | id
+-------+----
+ (0,1) | 1
+ (0,2) | 2
+(2 rows)
+
+FETCH BACKWARD 1 FROM c;
+ ctid | id
+-------+----
+ (0,2) | 2
+(1 row)
+
+FETCH FIRST FROM c;
+ ctid | id
+-------+----
+ (0,1) | 1
+(1 row)
+
+ROLLBACK;
+-- tidscan via CURRENT OF
+BEGIN;
+DECLARE c CURSOR FOR SELECT ctid, * FROM tidscan;
+FETCH NEXT FROM c; -- skip one row
+ ctid | id
+-------+----
+ (0,1) | 1
+(1 row)
+
+FETCH NEXT FROM c;
+ ctid | id
+-------+----
+ (0,2) | 2
+(1 row)
+
+-- perform update
+EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
+UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *;
+ QUERY PLAN
+---------------------------------------------------
+ Update on tidscan (actual rows=1 loops=1)
+ -> Tid Scan on tidscan (actual rows=1 loops=1)
+ TID Cond: CURRENT OF c
+(3 rows)
+
+FETCH NEXT FROM c;
+ ctid | id
+-------+----
+ (0,3) | 3
+(1 row)
+
+-- perform update
+EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
+UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *;
+ QUERY PLAN
+---------------------------------------------------
+ Update on tidscan (actual rows=1 loops=1)
+ -> Tid Scan on tidscan (actual rows=1 loops=1)
+ TID Cond: CURRENT OF c
+(3 rows)
+
+SELECT * FROM tidscan;
+ id
+----
+ 1
+ -2
+ -3
+(3 rows)
+
+-- position cursor past any rows
+FETCH NEXT FROM c;
+ ctid | id
+------+----
+(0 rows)
+
+-- should error out
+EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
+UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *;
+ERROR: cursor "c" is not positioned on a row
+ROLLBACK;
+DROP TABLE tidscan;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index ea7b5b4aa2..38743d98c3 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -89,7 +89,7 @@ test: brin gin gist spgist privileges init_privs security_label collate matview
# ----------
# Another group of parallel tests
# ----------
-test: alter_generic alter_operator misc psql async dbsize misc_functions sysviews tsrf
+test: alter_generic alter_operator misc psql async dbsize misc_functions sysviews tsrf tidscan
# rules cannot run concurrently with any test that creates a view
test: rules psql_crosstab amutils
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index cf48ea7cc8..d9f64c2873 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -129,6 +129,7 @@ test: dbsize
test: misc_functions
test: sysviews
test: tsrf
+test: tidscan
test: rules
test: psql_crosstab
test: select_parallel
diff --git a/src/test/regress/sql/tidscan.sql b/src/test/regress/sql/tidscan.sql
new file mode 100644
index 0000000000..a8472e09ac
--- /dev/null
+++ b/src/test/regress/sql/tidscan.sql
@@ -0,0 +1,66 @@
+-- tests for tidscans
+
+CREATE TABLE tidscan(id integer);
+
+-- only insert a few rows, we don't want to spill onto a second table page
+INSERT INTO tidscan VALUES (1), (2), (3);
+
+-- show ctids
+SELECT ctid, * FROM tidscan;
+
+-- ctid equality - implemented as tidscan
+EXPLAIN (COSTS OFF)
+SELECT ctid, * FROM tidscan WHERE ctid = '(0,1)';
+SELECT ctid, * FROM tidscan WHERE ctid = '(0,1)';
+
+EXPLAIN (COSTS OFF)
+SELECT ctid, * FROM tidscan WHERE '(0,1)' = ctid;
+SELECT ctid, * FROM tidscan WHERE '(0,1)' = ctid;
+
+-- ctid = ScalarArrayOp - implemented as tidscan
+EXPLAIN (COSTS OFF)
+SELECT ctid, * FROM tidscan WHERE ctid = ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
+SELECT ctid, * FROM tidscan WHERE ctid = ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
+
+-- ctid != ScalarArrayOp - can't be implemented as tidscan
+EXPLAIN (COSTS OFF)
+SELECT ctid, * FROM tidscan WHERE ctid != ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
+SELECT ctid, * FROM tidscan WHERE ctid != ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
+
+-- tid equality extracted from sub-AND clauses
+EXPLAIN (COSTS OFF)
+SELECT ctid, * FROM tidscan
+WHERE (id = 3 AND ctid IN ('(0,2)', '(0,3)')) OR (ctid = '(0,1)' AND id = 1);
+SELECT ctid, * FROM tidscan
+WHERE (id = 3 AND ctid IN ('(0,2)', '(0,3)')) OR (ctid = '(0,1)' AND id = 1);
+
+-- exercise backward scan and rewind
+BEGIN;
+DECLARE c CURSOR FOR
+SELECT ctid, * FROM tidscan WHERE ctid = ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
+FETCH ALL FROM c;
+FETCH BACKWARD 1 FROM c;
+FETCH FIRST FROM c;
+ROLLBACK;
+
+-- tidscan via CURRENT OF
+BEGIN;
+DECLARE c CURSOR FOR SELECT ctid, * FROM tidscan;
+FETCH NEXT FROM c; -- skip one row
+FETCH NEXT FROM c;
+-- perform update
+EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
+UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *;
+FETCH NEXT FROM c;
+-- perform update
+EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
+UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *;
+SELECT * FROM tidscan;
+-- position cursor past any rows
+FETCH NEXT FROM c;
+-- should error out
+EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
+UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *;
+ROLLBACK;
+
+DROP TABLE tidscan;