aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2017-03-20 12:30:08 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2017-03-20 12:30:23 -0400
commitbe6c3d19fd454359f05176eb1add82d4fc6e7758 (patch)
tree201685e8fabfcc20e55140cb66ec84cfdbd0aa35
parent9cf6033281fdaf938b826545a643f951086d8671 (diff)
downloadpostgresql-be6c3d19fd454359f05176eb1add82d4fc6e7758.tar.gz
postgresql-be6c3d19fd454359f05176eb1add82d4fc6e7758.zip
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 00000000000..521ed1b2f99
--- /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 ea7b5b4aa26..38743d98c34 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 cf48ea7cc8d..d9f64c28738 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 00000000000..a8472e09acd
--- /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;