Commit be6c3d19 authored by Tom Lane's avatar Tom Lane

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
parent 9cf60332
-- 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;
......@@ -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
......
......@@ -129,6 +129,7 @@ test: dbsize
test: misc_functions
test: sysviews
test: tsrf
test: tidscan
test: rules
test: psql_crosstab
test: select_parallel
......
-- 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;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment