1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-12 16:21:30 +03:00

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
This commit is contained in:
Tom Lane 2017-03-20 12:30:08 -04:00
parent 9cf6033281
commit be6c3d19fd
4 changed files with 247 additions and 1 deletions

View File

@ -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;

View File

@ -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

View File

@ -129,6 +129,7 @@ test: dbsize
test: misc_functions
test: sysviews
test: tsrf
test: tidscan
test: rules
test: psql_crosstab
test: select_parallel

View File

@ -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;