3 CREATE TABLE tidscan(id integer);
5 -- only insert a few rows, we don't want to spill onto a second table page
6 INSERT INTO tidscan VALUES (1), (2), (3);
9 SELECT ctid, * FROM tidscan;
11 -- ctid equality - implemented as tidscan
13 SELECT ctid, * FROM tidscan WHERE ctid = '(0,1)';
14 SELECT ctid, * FROM tidscan WHERE ctid = '(0,1)';
17 SELECT ctid, * FROM tidscan WHERE '(0,1)' = ctid;
18 SELECT ctid, * FROM tidscan WHERE '(0,1)' = ctid;
22 SELECT ctid, * FROM tidscan WHERE ctid = '(0,2)' OR '(0,1)' = ctid;
23 SELECT ctid, * FROM tidscan WHERE ctid = '(0,2)' OR '(0,1)' = ctid;
25 -- ctid = ScalarArrayOp - implemented as tidscan
27 SELECT ctid, * FROM tidscan WHERE ctid = ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
28 SELECT ctid, * FROM tidscan WHERE ctid = ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
30 -- ctid != ScalarArrayOp - can't be implemented as tidscan
32 SELECT ctid, * FROM tidscan WHERE ctid != ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
33 SELECT ctid, * FROM tidscan WHERE ctid != ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
35 -- tid equality extracted from sub-AND clauses
37 SELECT ctid, * FROM tidscan
38 WHERE (id = 3 AND ctid IN ('(0,2)', '(0,3)')) OR (ctid = '(0,1)' AND id = 1);
39 SELECT ctid, * FROM tidscan
40 WHERE (id = 3 AND ctid IN ('(0,2)', '(0,3)')) OR (ctid = '(0,1)' AND id = 1);
42 -- nestloop-with-inner-tidscan joins on tid
43 SET enable_hashjoin TO off; -- otherwise hash join might win
45 SELECT t1.ctid, t1.*, t2.ctid, t2.*
46 FROM tidscan t1 JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1;
47 SELECT t1.ctid, t1.*, t2.ctid, t2.*
48 FROM tidscan t1 JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1;
50 SELECT t1.ctid, t1.*, t2.ctid, t2.*
51 FROM tidscan t1 LEFT JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1;
52 SELECT t1.ctid, t1.*, t2.ctid, t2.*
53 FROM tidscan t1 LEFT JOIN tidscan t2 ON t1.ctid = t2.ctid WHERE t1.id = 1;
54 RESET enable_hashjoin;
56 -- exercise backward scan and rewind
59 SELECT ctid, * FROM tidscan WHERE ctid = ANY(ARRAY['(0,1)', '(0,2)']::tid[]);
61 FETCH BACKWARD 1 FROM c;
65 -- tidscan via CURRENT OF
67 DECLARE c CURSOR FOR SELECT ctid, * FROM tidscan;
68 FETCH NEXT FROM c; -- skip one row
71 EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF)
72 UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *;
75 EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF)
76 UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *;
77 SELECT * FROM tidscan;
78 -- position cursor past any rows
81 EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, BUFFERS OFF)
82 UPDATE tidscan SET id = -id WHERE CURRENT OF c RETURNING *;
86 -- (these plans don't use TID scans, but this still seems like an
87 -- appropriate place for these tests)
89 SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
90 SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
91 SET enable_hashjoin TO off;
93 SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
94 SELECT count(*) FROM tenk1 t1 JOIN tenk1 t2 ON t1.ctid = t2.ctid;
95 RESET enable_hashjoin;
97 -- check predicate lock on CTID
98 BEGIN ISOLATION LEVEL SERIALIZABLE;
99 SELECT * FROM tidscan WHERE ctid = '(0,1)';
100 -- locktype should be 'tuple'
101 SELECT locktype, mode FROM pg_locks WHERE pid = pg_backend_pid() AND mode = 'SIReadLock';