-- directory paths are passed to us in environment variables
\getenv abs_srcdir PG_ABS_SRCDIR
-- -- BTREE -- CREATEINDEX onek_unique1 ON onek USING btree(unique1 int4_ops);
CREATEINDEXIFNOTEXISTS onek_unique1 ON onek USING btree(unique1 int4_ops);
CREATEINDEXIFNOTEXISTSON onek USING btree(unique1 int4_ops);
CREATEINDEX onek_unique2 ON onek USING btree(unique2 int4_ops);
CREATEINDEX onek_hundred ON onek USING btree(hundred int4_ops);
CREATEINDEX onek_stringu1 ON onek USING btree(stringu1 name_ops);
CREATEINDEX tenk1_unique1 ON tenk1 USING btree(unique1 int4_ops);
CREATEINDEX tenk1_unique2 ON tenk1 USING btree(unique2 int4_ops);
CREATEINDEX tenk1_hundred ON tenk1 USING btree(hundred int4_ops);
CREATEINDEX tenk1_thous_tenthous ON tenk1 (thousand, tenthous);
CREATEINDEX tenk2_unique1 ON tenk2 USING btree(unique1 int4_ops);
CREATEINDEX tenk2_unique2 ON tenk2 USING btree(unique2 int4_ops);
CREATEINDEX tenk2_hundred ON tenk2 USING btree(hundred int4_ops);
CREATEINDEX rix ON road USING btree (name text_ops);
CREATEINDEX iix ON ihighway USING btree (name text_ops);
CREATEINDEX six ON shighway USING btree (name text_ops);
-- test comments
COMMENT ONINDEX six_wrong IS'bad index';
COMMENT ONINDEX six IS'good index';
COMMENT ONINDEX six ISNULL; SELECT obj_description('six'::regclass, 'pg_class') ISNULLAS six_comment_is_null;
COMMENT ONINDEX six IS'add the comment back';
COMMENT ONINDEX six IS''; -- empty string removes the comment, same as NULL SELECT obj_description('six'::regclass, 'pg_class') ISNULLAS six_comment_is_null;
-- -- BTREE partial indices -- CREATEINDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops) where unique1 < 20or unique1 > 980;
CREATEINDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops) where stringu1 < 'B';
CREATEINDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops) where onek2.stringu1 >= 'J'and onek2.stringu1 < 'K';
-- -- GiST (rtree-equivalent opclasses only) --
CREATETABLE slow_emp4000 (
home_base box
);
CREATETABLE fast_emp4000 (
home_base box
);
\set filename :abs_srcdir '/data/rect.data'
COPY slow_emp4000 FROM :'filename';
INSERTINTO fast_emp4000 SELECT * FROM slow_emp4000;
ANALYZE slow_emp4000; ANALYZE fast_emp4000;
CREATEINDEX grect2ind ON fast_emp4000 USING gist (home_base);
-- we want to work with a point_tbl that includes a null CREATE TEMP TABLE point_tbl ASSELECT * FROM public.point_tbl; INSERTINTO POINT_TBL(f1) VALUES (NULL);
CREATEINDEX gpointind ON point_tbl USING gist (f1);
CREATE TEMP TABLE gpolygon_tbl AS SELECT polygon(home_base) AS f1 FROM slow_emp4000; INSERTINTO gpolygon_tbl VALUES ( '(1000,0,0,1000)' ); INSERTINTO gpolygon_tbl VALUES ( '(0,1000,1000,1000)' );
CREATE TEMP TABLE gcircle_tbl AS SELECT circle(home_base) AS f1 FROM slow_emp4000;
CREATEINDEX ggpolygonind ON gpolygon_tbl USING gist (f1);
CREATEINDEX ggcircleind ON gcircle_tbl USING gist (f1);
-- -- Test GiST indexes --
-- get non-indexed results for comparison purposes
SET enable_seqscan = ON; SET enable_indexscan = OFF; SET enable_bitmapscan = OFF;
SELECT * FROM fast_emp4000 WHERE home_base <@ '(200,200),(2000,1000)'::box ORDERBY (home_base[0])[0];
SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box;
SELECT count(*) FROM fast_emp4000 WHERE home_base ISNULL;
SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon;
SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
SELECT count(*) FROM point_tbl p WHERE p.f1 <<| '(0.0, 0.0)';
SELECT count(*) FROM point_tbl p WHERE p.f1 |>> '(0.0, 0.0)';
SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
SELECT * FROM point_tbl ORDERBY f1 <-> '0,1';
SELECT * FROM point_tbl WHERE f1 ISNULL;
SELECT * FROM point_tbl WHERE f1 ISNOTNULLORDERBY f1 <-> '0,1';
SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDERBY f1 <-> '0,1';
SELECT * FROM gpolygon_tbl ORDERBY f1 <-> '(0,0)'::point LIMIT10;
SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDERBY f1 <-> '(200,300)'::point LIMIT10;
-- Now check the results from plain indexscan SET enable_seqscan = OFF; SET enable_indexscan = ON; SET enable_bitmapscan = OFF;
EXPLAIN (COSTS OFF) SELECT * FROM fast_emp4000 WHERE home_base <@ '(200,200),(2000,1000)'::box ORDERBY (home_base[0])[0]; SELECT * FROM fast_emp4000 WHERE home_base <@ '(200,200),(2000,1000)'::box ORDERBY (home_base[0])[0];
EXPLAIN (COSTS OFF) SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box; SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box;
EXPLAIN (COSTS OFF) SELECT count(*) FROM fast_emp4000 WHERE home_base ISNULL; SELECT count(*) FROM fast_emp4000 WHERE home_base ISNULL;
EXPLAIN (COSTS OFF) SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon; SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon;
EXPLAIN (COSTS OFF) SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle; SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)'; SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1; SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)'; SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>'; SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)'; SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)'; SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl p WHERE p.f1 <<| '(0.0, 0.0)'; SELECT count(*) FROM point_tbl p WHERE p.f1 <<| '(0.0, 0.0)';
EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl p WHERE p.f1 |>> '(0.0, 0.0)'; SELECT count(*) FROM point_tbl p WHERE p.f1 |>> '(0.0, 0.0)';
EXPLAIN (COSTS OFF) SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)'; SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
EXPLAIN (COSTS OFF) SELECT * FROM point_tbl ORDERBY f1 <-> '0,1'; SELECT * FROM point_tbl ORDERBY f1 <-> '0,1';
EXPLAIN (COSTS OFF) SELECT * FROM point_tbl WHERE f1 ISNULL; SELECT * FROM point_tbl WHERE f1 ISNULL;
EXPLAIN (COSTS OFF) SELECT * FROM point_tbl WHERE f1 ISNOTNULLORDERBY f1 <-> '0,1'; SELECT * FROM point_tbl WHERE f1 ISNOTNULLORDERBY f1 <-> '0,1';
EXPLAIN (COSTS OFF) SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDERBY f1 <-> '0,1'; SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDERBY f1 <-> '0,1';
EXPLAIN (COSTS OFF) SELECT * FROM gpolygon_tbl ORDERBY f1 <-> '(0,0)'::point LIMIT10; SELECT * FROM gpolygon_tbl ORDERBY f1 <-> '(0,0)'::point LIMIT10;
EXPLAIN (COSTS OFF) SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDERBY f1 <-> '(200,300)'::point LIMIT10; SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDERBY f1 <-> '(200,300)'::point LIMIT10;
EXPLAIN (COSTS OFF) SELECT point(x,x), (SELECT f1 FROM gpolygon_tbl ORDERBY f1 <-> point(x,x) LIMIT1) as c FROM generate_series(0,10,1) x; SELECT point(x,x), (SELECT f1 FROM gpolygon_tbl ORDERBY f1 <-> point(x,x) LIMIT1) as c FROM generate_series(0,10,1) x;
-- Now check the results from bitmap indexscan SET enable_seqscan = OFF; SET enable_indexscan = OFF; SET enable_bitmapscan = ON;
EXPLAIN (COSTS OFF) SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDERBY f1 <-> '0,1'; SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDERBY f1 <-> '0,1';
-- -- GIN over int[] and text[] -- -- Note: GIN currently supports only bitmap scans, not plain indexscans --
CREATETABLE array_index_op_test (
seqno int4,
i int4[],
t text[]
);
\set filename :abs_srcdir '/data/array.data'
COPY array_index_op_test FROM :'filename'; ANALYZE array_index_op_test;
SELECT * FROM array_index_op_test WHERE i = '{NULL}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i @> '{NULL}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i && '{NULL}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i <@ '{NULL}'ORDERBY seqno;
SET enable_seqscan = OFF; SET enable_indexscan = OFF; SET enable_bitmapscan = ON;
CREATEINDEX intarrayidx ON array_index_op_test USING gin (i);
explain (costs off) SELECT * FROM array_index_op_test WHERE i @> '{32}'ORDERBY seqno;
SELECT * FROM array_index_op_test WHERE i @> '{32}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i && '{32}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i @> '{17}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i && '{17}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i @> '{32,17}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i && '{32,17}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i <@ '{38,34,32,89}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i = '{47,77}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i = '{}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i @> '{}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i && '{}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i <@ '{}'ORDERBY seqno;
CREATEINDEX textarrayidx ON array_index_op_test USING gin (t);
explain (costs off) SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAA72908}'ORDERBY seqno;
SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAA72908}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t && '{AAAAAAAA72908}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAAAA646}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t && '{AAAAAAAAAA646}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAA72908,AAAAAAAAAA646}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t && '{AAAAAAAA72908,AAAAAAAAAA646}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t <@ '{AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t = '{AAAAAAAAAA646,A87088}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t = '{}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t @> '{}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t && '{}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t <@ '{}'ORDERBY seqno;
-- And try it with a multicolumn GIN index
DROPINDEX intarrayidx, textarrayidx;
CREATEINDEX botharrayidx ON array_index_op_test USING gin (i, t);
SELECT * FROM array_index_op_test WHERE i @> '{32}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i && '{32}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAA80240}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t && '{AAAAAAA80240}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i @> '{32}'AND t && '{AAAAAAA80240}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE i && '{32}'AND t @> '{AAAAAAA80240}'ORDERBY seqno; SELECT * FROM array_index_op_test WHERE t = '{}'ORDERBY seqno;
-- -- Try a GIN index with a lot of items with same key. (GIN creates a posting -- tree when there are enough duplicates) -- CREATETABLE array_gin_test (a int[]);
INSERTINTO array_gin_test SELECT ARRAY[1, g%5, g] FROM generate_series(1, 10000) g;
CREATEINDEX array_gin_test_idx ON array_gin_test USING gin (a);
SELECT COUNT(*) FROM array_gin_test WHERE a @> '{2}';
DROPTABLE array_gin_test;
-- -- Test GIN index's reloptions -- CREATEINDEX gin_relopts_test ON array_index_op_test USING gin (i) WITH (FASTUPDATE=on, GIN_PENDING_LIST_LIMIT=128);
\d+ gin_relopts_test
-- -- HASH -- CREATE UNLOGGED TABLE unlogged_hash_table (id int4); CREATEINDEX unlogged_hash_index ON unlogged_hash_table USING hash (id int4_ops); DROPTABLE unlogged_hash_table;
-- CREATE INDEX hash_ovfl_index ON hash_ovfl_heap USING hash (x int4_ops);
-- Test hash index build tuplesorting. Force hash tuplesort using low -- maintenance_work_mem setting and fillfactor: SET maintenance_work_mem = '1MB'; CREATEINDEX hash_tuplesort_idx ON tenk1 USING hash (stringu1 name_ops) WITH (fillfactor = 10); EXPLAIN (COSTS OFF) SELECT count(*) FROM tenk1 WHERE stringu1 = 'TVAAAA'; SELECT count(*) FROM tenk1 WHERE stringu1 = 'TVAAAA'; -- OR-clauses shouldn't be transformed into SAOP because hash indexes don't -- support SAOP scans. SET enable_seqscan = off; EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM tenk1 WHERE stringu1 = 'TVAAAA'OR stringu1 = 'TVAAAB';
RESET enable_seqscan; DROPINDEX hash_tuplesort_idx;
RESET maintenance_work_mem;
-- -- Test unique null behavior -- CREATETABLE unique_tbl (i int, t text);
CREATEUNIQUEINDEX unique_idx1 ON unique_tbl (i) NULLS DISTINCT; CREATEUNIQUEINDEX unique_idx2 ON unique_tbl (i) NULLS NOTDISTINCT;
-- -- Test functional index -- CREATETABLE func_index_heap (f1 text, f2 text); CREATEUNIQUEINDEX func_index_index on func_index_heap (textcat(f1,f2));
INSERTINTO func_index_heap VALUES('ABC','DEF'); INSERTINTO func_index_heap VALUES('AB','CDEFG'); INSERTINTO func_index_heap VALUES('QWE','RTY'); -- this should fail because of unique index: INSERTINTO func_index_heap VALUES('ABCD', 'EF'); -- but this shouldn't: INSERTINTO func_index_heap VALUES('QWERTY');
-- while we're here, see that the metadata looks sane
\d func_index_heap
\d func_index_index
-- -- Same test, expressional index -- DROPTABLE func_index_heap; CREATETABLE func_index_heap (f1 text, f2 text); CREATEUNIQUEINDEX func_index_index on func_index_heap ((f1 || f2) text_ops);
INSERTINTO func_index_heap VALUES('ABC','DEF'); INSERTINTO func_index_heap VALUES('AB','CDEFG'); INSERTINTO func_index_heap VALUES('QWE','RTY'); -- this should fail because of unique index: INSERTINTO func_index_heap VALUES('ABCD', 'EF'); -- but this shouldn't: INSERTINTO func_index_heap VALUES('QWERTY');
-- while we're here, see that the metadata looks sane
\d func_index_heap
\d func_index_index
-- this should fail because of unsafe column type (anonymous record) createindexon func_index_heap ((f1 || f2), (row(f1, f2)));
-- -- Test unique index with included columns -- CREATETABLE covering_index_heap (f1 int, f2 int, f3 text); CREATEUNIQUEINDEX covering_index_index on covering_index_heap (f1,f2) INCLUDE(f3);
INSERTINTO covering_index_heap VALUES(1,1,'AAA'); INSERTINTO covering_index_heap VALUES(1,2,'AAA'); -- this should fail because of unique index on f1,f2: INSERTINTO covering_index_heap VALUES(1,2,'BBB'); -- and this shouldn't: INSERTINTO covering_index_heap VALUES(1,4,'AAA'); -- Try to build index on table that already contains data CREATEUNIQUEINDEX covering_pkey on covering_index_heap (f1,f2) INCLUDE(f3); -- Try to use existing covering index as primary key ALTERTABLE covering_index_heap ADDCONSTRAINT covering_pkey PRIMARYKEYUSINGINDEX
covering_pkey; DROPTABLE covering_index_heap;
-- -- Try some concurrent index builds -- -- Unfortunately this only tests about half the code paths because there are -- no concurrent updates happening to the table at the same time.
CREATETABLE concur_heap (f1 text, f2 text); -- empty table CREATEINDEX CONCURRENTLY concur_index1 ON concur_heap(f2,f1); CREATEINDEX CONCURRENTLY IFNOTEXISTS concur_index1 ON concur_heap(f2,f1); INSERTINTO concur_heap VALUES ('a','b'); INSERTINTO concur_heap VALUES ('b','b'); -- unique index CREATEUNIQUEINDEX CONCURRENTLY concur_index2 ON concur_heap(f1); CREATEUNIQUEINDEX CONCURRENTLY IFNOTEXISTS concur_index2 ON concur_heap(f1); -- check if constraint is set up properly to be enforced INSERTINTO concur_heap VALUES ('b','x'); -- check if constraint is enforced properly at build time CREATEUNIQUEINDEX CONCURRENTLY concur_index3 ON concur_heap(f2); -- test that expression indexes and partial indexes work concurrently CREATEINDEX CONCURRENTLY concur_index4 on concur_heap(f2) WHERE f1='a'; CREATEINDEX CONCURRENTLY concur_index5 on concur_heap(f2) WHERE f1='x'; -- here we also check that you can default the index name CREATEINDEX CONCURRENTLY on concur_heap((f2||f1)); -- You can't do a concurrent index build in a transaction
BEGIN; CREATEINDEX CONCURRENTLY concur_index7 ON concur_heap(f1); COMMIT; -- test where predicate is able to do a transactional update during -- a concurrent build before switching pg_index state flags. CREATE FUNCTION predicate_stable() RETURNS bool IMMUTABLE
LANGUAGE plpgsql AS $$
BEGIN
EXECUTE 'SELECT txid_current()'; RETURNtrue;
END; $$; CREATEINDEX CONCURRENTLY concur_index8 ON concur_heap (f1) WHERE predicate_stable(); DROPINDEX concur_index8; DROP FUNCTION predicate_stable();
-- But you can do a regular index build in a transaction
BEGIN; CREATEINDEX std_index on concur_heap(f2); COMMIT;
-- Failed builds are left invalid by VACUUM FULL, fixed by REINDEX
VACUUM FULL concur_heap;
REINDEX TABLE concur_heap; DELETEFROM concur_heap WHERE f1 = 'b';
VACUUM FULL concur_heap;
\d concur_heap
REINDEX TABLE concur_heap;
\d concur_heap
-- Temporary tables with concurrent builds and on-commit actions -- CONCURRENTLY used with CREATE INDEX and DROP INDEX is ignored. -- PRESERVE ROWS, the default. CREATE TEMP TABLE concur_temp (f1 int, f2 text) ONCOMMIT PRESERVE ROWS; INSERTINTO concur_temp VALUES (1, 'foo'), (2, 'bar'); CREATEINDEX CONCURRENTLY concur_temp_ind ON concur_temp(f1); DROPINDEX CONCURRENTLY concur_temp_ind; DROPTABLE concur_temp; -- ON COMMIT DROP
BEGIN; CREATE TEMP TABLE concur_temp (f1 int, f2 text) ONCOMMITDROP; INSERTINTO concur_temp VALUES (1, 'foo'), (2, 'bar'); -- Fails when running in a transaction. CREATEINDEX CONCURRENTLY concur_temp_ind ON concur_temp(f1); COMMIT; -- ON COMMIT DELETE ROWS CREATE TEMP TABLE concur_temp (f1 int, f2 text) ONCOMMITDELETE ROWS; INSERTINTO concur_temp VALUES (1, 'foo'), (2, 'bar'); CREATEINDEX CONCURRENTLY concur_temp_ind ON concur_temp(f1); DROPINDEX CONCURRENTLY concur_temp_ind; DROPTABLE concur_temp;
-- -- Try some concurrent index drops -- DROPINDEX CONCURRENTLY "concur_index2"; -- works DROPINDEX CONCURRENTLY IFEXISTS"concur_index2"; -- notice
DROPINDEX cwi_replaced_pkey; -- Should fail; a constraint depends on it
-- Check that non-default index options are rejected CREATEUNIQUEINDEX cwi_uniq3_idx ON cwi_test(a desc); ALTERTABLE cwi_test ADDUNIQUEUSINGINDEX cwi_uniq3_idx; -- fail CREATEUNIQUEINDEX cwi_uniq4_idx ON cwi_test(b collate"POSIX"); ALTERTABLE cwi_test ADDUNIQUEUSINGINDEX cwi_uniq4_idx; -- fail
DROPTABLE cwi_test;
-- ADD CONSTRAINT USING INDEX is forbidden on partitioned tables CREATETABLE cwi_test(a int) PARTITION BY hash (a); createuniqueindexon cwi_test (a); altertable cwi_test addprimarykeyusingindex cwi_test_a_idx ; DROPTABLE cwi_test;
-- PRIMARY KEY constraint cannot be backed by a NULLS NOT DISTINCT index CREATETABLE cwi_test(a int, b int); CREATEUNIQUEINDEX cwi_a_nnd ON cwi_test (a) NULLS NOTDISTINCT; ALTERTABLE cwi_test ADDPRIMARYKEYUSINGINDEX cwi_a_nnd; DROPTABLE cwi_test;
-- -- Check handling of indexes on system columns -- CREATETABLE syscol_table (a INT);
-- System columns cannot be indexed CREATEINDEXON syscol_table (ctid);
-- nor used in expressions CREATEINDEXON syscol_table ((ctid >= '(1000,0)'));
-- nor used in predicates CREATEINDEXON syscol_table (a) WHERE ctid >= '(1000,0)';
DROPTABLE syscol_table;
-- -- Tests for IS NULL/IS NOT NULL with b-tree indexes --
SET enable_seqscan = OFF; SET enable_indexscan = ON; SET enable_bitmapscan = ON;
SELECT count(*) FROM onek_with_null WHERE unique1 ISNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique2 ISNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNOTNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique2 ISNOTNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNOTNULLAND unique1 > 500; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique1 > 500; SELECT unique1, unique2 FROM onek_with_null WHERE unique1 = 500ORDERBY unique2 DESC, unique1 DESCLIMIT1;
DROPINDEX onek_nulltest;
CREATEUNIQUEINDEX onek_nulltest ON onek_with_null (unique2 desc,unique1);
SELECT count(*) FROM onek_with_null WHERE unique1 ISNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique2 ISNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNOTNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique2 ISNOTNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNOTNULLAND unique1 > 500; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique1 > 500; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique2 IN (-1, 0, 1); SELECT unique1, unique2 FROM onek_with_null WHERE unique1 = 500ORDERBY unique2 DESC, unique1 DESCLIMIT1;
DROPINDEX onek_nulltest;
CREATEUNIQUEINDEX onek_nulltest ON onek_with_null (unique2 desc nulls last,unique1);
SELECT count(*) FROM onek_with_null WHERE unique1 ISNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique2 ISNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNOTNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique2 ISNOTNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNOTNULLAND unique1 > 500; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique1 > 500; SELECT unique1, unique2 FROM onek_with_null WHERE unique1 = 500ORDERBY unique2 DESC, unique1 DESCLIMIT1;
DROPINDEX onek_nulltest;
CREATEUNIQUEINDEX onek_nulltest ON onek_with_null (unique2 nulls first,unique1);
SELECT count(*) FROM onek_with_null WHERE unique1 ISNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique2 ISNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNOTNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique2 ISNOTNULL; SELECT count(*) FROM onek_with_null WHERE unique1 ISNOTNULLAND unique1 > 500; SELECT count(*) FROM onek_with_null WHERE unique1 ISNULLAND unique1 > 500; SELECT unique1, unique2 FROM onek_with_null WHERE unique1 = 500ORDERBY unique2 DESC, unique1 DESCLIMIT1;
DROPINDEX onek_nulltest;
-- Check initial-positioning logic too
CREATEUNIQUEINDEX onek_nulltest ON onek_with_null (unique2);
SET enable_seqscan = OFF; SET enable_indexscan = ON; SET enable_bitmapscan = OFF;
SELECT unique1, unique2 FROM onek_with_null ORDERBY unique2 LIMIT2; SELECT unique1, unique2 FROM onek_with_null WHERE unique2 >= -1 ORDERBY unique2 LIMIT2; SELECT unique1, unique2 FROM onek_with_null WHERE unique2 >= 0 ORDERBY unique2 LIMIT2;
SELECT unique1, unique2 FROM onek_with_null ORDERBY unique2 DESCLIMIT5; SELECT unique1, unique2 FROM onek_with_null WHERE unique2 >= -1 ORDERBY unique2 DESCLIMIT3; SELECT unique1, unique2 FROM onek_with_null WHERE unique2 < 999 ORDERBY unique2 DESCLIMIT2;
EXPLAIN (COSTS OFF) SELECT count(*) FROM tenk1, tenk2 WHERE tenk1.hundred = 42AND (tenk2.thousand = 42OR tenk1.thousand = 41OR tenk2.tenthous = 2) AND
tenk2.hundred = tenk1.hundred;
EXPLAIN (COSTS OFF) SELECT count(*) FROM tenk1, tenk2 WHERE tenk1.hundred = 42AND (tenk2.thousand = 42OR tenk2.thousand = 41OR tenk2.tenthous = 2) AND
tenk2.hundred = tenk1.hundred;
EXPLAIN (COSTS OFF) SELECT count(*) FROM tenk1 JOIN tenk2 ON
tenk1.hundred = 42AND (tenk2.thousand = 42OR tenk2.thousand = 41OR tenk2.tenthous = 2) AND
tenk2.hundred = tenk1.hundred;
EXPLAIN (COSTS OFF) SELECT count(*) FROM tenk1 LEFTJOIN tenk2 ON
tenk1.hundred = 42AND (tenk2.thousand = 42OR tenk2.thousand = 41OR tenk2.tenthous = 2) AND
tenk2.hundred = tenk1.hundred; -- -- Check behavior with duplicate index column contents --
CREATETABLE dupindexcols AS SELECT unique1 as id, stringu2::text as f1 FROM tenk1; CREATEINDEX dupindexcols_i ON dupindexcols (f1, id, f1 text_pattern_ops); ANALYZE dupindexcols;
EXPLAIN (COSTS OFF) SELECT count(*) FROM dupindexcols WHERE f1 BETWEEN'WA'AND'ZZZ'and id < 1000and f1 ~<~ 'YX'; SELECT count(*) FROM dupindexcols WHERE f1 BETWEEN'WA'AND'ZZZ'and id < 1000and f1 ~<~ 'YX';
-- -- Check that index scans with SAOP array and/or skip array indexquals -- return rows in index order --
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 IN (1,42,7) ORDERBY unique1;
SELECT unique1 FROM tenk1 WHERE unique1 IN (1,42,7) ORDERBY unique1;
-- Skip array on "thousand", SAOP array on "tenthous": explain (costs off) SELECT thousand, tenthous FROM tenk1 WHERE thousand < 2AND tenthous IN (1001,3000) ORDERBY thousand;
SELECT thousand, tenthous FROM tenk1 WHERE thousand < 2AND tenthous IN (1001,3000) ORDERBY thousand;
-- Skip array on "thousand", SAOP array on "tenthous", backward scan: explain (costs off) SELECT thousand, tenthous FROM tenk1 WHERE thousand < 2AND tenthous IN (1001,3000) ORDERBY thousand DESC, tenthous DESC;
SELECT thousand, tenthous FROM tenk1 WHERE thousand < 2AND tenthous IN (1001,3000) ORDERBY thousand DESC, tenthous DESC;
explain (costs off) SELECT thousand, tenthous FROM tenk1 WHERE thousand > 995and tenthous in (998, 999) ORDERBY thousand desc;
SELECT thousand, tenthous FROM tenk1 WHERE thousand > 995and tenthous in (998, 999) ORDERBY thousand desc;
-- -- Check elimination of redundant and contradictory index quals -- explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = ANY('{7, 8, 9}');
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = ANY('{7, 8, 9}');
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 = ANY('{7, 14, 22}') and unique1 = ANY('{33, 44}'::bigint[]);
SELECT unique1 FROM tenk1 WHERE unique1 = ANY('{7, 14, 22}') and unique1 = ANY('{33, 44}'::bigint[]);
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 = ANY(NULL);
SELECT unique1 FROM tenk1 WHERE unique1 = ANY(NULL);
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 = ANY('{NULL,NULL,NULL}');
SELECT unique1 FROM tenk1 WHERE unique1 = ANY('{NULL,NULL,NULL}');
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 ISNULLAND unique1 ISNULL;
SELECT unique1 FROM tenk1 WHERE unique1 ISNULLAND unique1 ISNULL;
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 1;
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 1;
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 12345;
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 12345;
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 >= 42;
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 >= 42;
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 > 42;
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 > 42;
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 > 9996and unique1 >= 9999;
SELECT unique1 FROM tenk1 WHERE unique1 > 9996and unique1 >= 9999;
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 < 3and unique1 <= 3;
SELECT unique1 FROM tenk1 WHERE unique1 < 3and unique1 <= 3;
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 < 3and unique1 < (-1)::bigint;
SELECT unique1 FROM tenk1 WHERE unique1 < 3and unique1 < (-1)::bigint;
explain (costs off) SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 < (-1)::bigint;
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 < (-1)::bigint;
explain (costs off) SELECT unique1 FROM tenk1 WHERE (thousand, tenthous) > (NULL, 5);
SELECT unique1 FROM tenk1 WHERE (thousand, tenthous) > (NULL, 5);
-- Skip array redundancy (pair of redundant low_compare inequalities) explain (costs off) SELECT thousand, tenthous FROM tenk1 WHERE thousand > -1and thousand >= 0AND tenthous = 3000 ORDERBY thousand;
SELECT thousand, tenthous FROM tenk1 WHERE thousand > -1and thousand >= 0AND tenthous = 3000 ORDERBY thousand;
-- Skip array redundancy (pair of redundant high_compare inequalities) explain (costs off) SELECT thousand, tenthous FROM tenk1 WHERE thousand < 3and thousand <= 2AND tenthous = 1001 ORDERBY thousand;
SELECT thousand, tenthous FROM tenk1 WHERE thousand < 3and thousand <= 2AND tenthous = 1001 ORDERBY thousand;
-- Skip array preprocessing increments "thousand > -1" to "thousand >= 0" explain (costs off) SELECT thousand, tenthous FROM tenk1 WHERE thousand > -1AND tenthous IN (1001,3000) ORDERBY thousand limit2;
SELECT thousand, tenthous FROM tenk1 WHERE thousand > -1AND tenthous IN (1001,3000) ORDERBY thousand limit2;
-- -- Check elimination of constant-NULL subexpressions --
explain (costs off) select * from tenk1 where (thousand, tenthous) in ((1,1001), (null,null));
-- -- Check matching of boolean index columns to WHERE conditions and sort keys --
explain (costs off) select * from boolindex orderby b, i limit10; explain (costs off) select * from boolindex where b orderby i limit10; explain (costs off) select * from boolindex where b = trueorderby i desclimit10; explain (costs off) select * from boolindex wherenot b orderby i limit10; explain (costs off) select * from boolindex where b istrueorderby i desclimit10; explain (costs off) select * from boolindex where b isfalseorderby i desclimit10;
-- -- REINDEX CONCURRENTLY -- CREATETABLE concur_reindex_tab (c1 int); -- REINDEX
REINDEX TABLE concur_reindex_tab; -- notice
REINDEX (CONCURRENTLY) TABLE concur_reindex_tab; -- notice ALTERTABLE concur_reindex_tab ADDCOLUMN c2 text; -- add toast index -- Normal index with integer column CREATEUNIQUEINDEX concur_reindex_ind1 ON concur_reindex_tab(c1); -- Normal index with text column CREATEINDEX concur_reindex_ind2 ON concur_reindex_tab(c2); -- UNIQUE index with expression CREATEUNIQUEINDEX concur_reindex_ind3 ON concur_reindex_tab(abs(c1)); -- Duplicate column names CREATEINDEX concur_reindex_ind4 ON concur_reindex_tab(c1, c1, c2); -- Create table for check on foreign key dependence switch with indexes swapped ALTERTABLE concur_reindex_tab ADDPRIMARYKEYUSINGINDEX concur_reindex_ind1; CREATETABLE concur_reindex_tab2 (c1 intREFERENCES concur_reindex_tab); INSERTINTO concur_reindex_tab VALUES (1, 'a'); INSERTINTO concur_reindex_tab VALUES (2, 'a'); -- Reindex concurrently of exclusion constraint currently not supported CREATETABLE concur_reindex_tab3 (c1 int, c2 int4range, EXCLUDE USING gist (c2 WITH &&)); INSERTINTO concur_reindex_tab3 VALUES (3, '[1,2]');
REINDEX INDEX CONCURRENTLY concur_reindex_tab3_c2_excl; -- error
REINDEX TABLE CONCURRENTLY concur_reindex_tab3; -- succeeds with warning INSERTINTO concur_reindex_tab3 VALUES (4, '[2,4]'); -- Check materialized views CREATE MATERIALIZED VIEW concur_reindex_matview ASSELECT * FROM concur_reindex_tab; -- Dependency lookup before and after the follow-up REINDEX commands. -- These should remain consistent. SELECT pg_describe_object(classid, objid, objsubid) as obj,
pg_describe_object(refclassid,refobjid,refobjsubid) as objref,
deptype FROM pg_depend WHERE classid = 'pg_class'::regclass AND
objid in ('concur_reindex_tab'::regclass, 'concur_reindex_ind1'::regclass, 'concur_reindex_ind2'::regclass, 'concur_reindex_ind3'::regclass, 'concur_reindex_ind4'::regclass, 'concur_reindex_matview'::regclass) ORDERBY1, 2;
REINDEX INDEX CONCURRENTLY concur_reindex_ind1;
REINDEX TABLE CONCURRENTLY concur_reindex_tab;
REINDEX TABLE CONCURRENTLY concur_reindex_matview; SELECT pg_describe_object(classid, objid, objsubid) as obj,
pg_describe_object(refclassid,refobjid,refobjsubid) as objref,
deptype FROM pg_depend WHERE classid = 'pg_class'::regclass AND
objid in ('concur_reindex_tab'::regclass, 'concur_reindex_ind1'::regclass, 'concur_reindex_ind2'::regclass, 'concur_reindex_ind3'::regclass, 'concur_reindex_ind4'::regclass, 'concur_reindex_matview'::regclass) ORDERBY1, 2; -- Check that comments are preserved CREATETABLE testcomment (i int); CREATEINDEX testcomment_idx1 ON testcomment (i);
COMMENT ONINDEX testcomment_idx1 IS'test comment'; SELECT obj_description('testcomment_idx1'::regclass, 'pg_class');
REINDEX TABLE testcomment; SELECT obj_description('testcomment_idx1'::regclass, 'pg_class');
REINDEX TABLE CONCURRENTLY testcomment ; SELECT obj_description('testcomment_idx1'::regclass, 'pg_class'); DROPTABLE testcomment; -- Check that indisclustered updates are preserved CREATETABLE concur_clustered(i int); CREATEINDEX concur_clustered_i_idx ON concur_clustered(i); ALTERTABLE concur_clustered CLUSTER ON concur_clustered_i_idx;
REINDEX TABLE CONCURRENTLY concur_clustered; SELECT indexrelid::regclass, indisclustered FROM pg_index WHERE indrelid = 'concur_clustered'::regclass; DROPTABLE concur_clustered; -- Check that indisreplident updates are preserved. CREATETABLE concur_replident(i intNOTNULL); CREATEUNIQUEINDEX concur_replident_i_idx ON concur_replident(i); ALTERTABLE concur_replident REPLICA IDENTITY USINGINDEX concur_replident_i_idx; SELECT indexrelid::regclass, indisreplident FROM pg_index WHERE indrelid = 'concur_replident'::regclass;
REINDEX TABLE CONCURRENTLY concur_replident; SELECT indexrelid::regclass, indisreplident FROM pg_index WHERE indrelid = 'concur_replident'::regclass; DROPTABLE concur_replident; -- Check that opclass parameters are preserved CREATETABLE concur_appclass_tab(i tsvector, j tsvector, k tsvector); CREATEINDEX concur_appclass_ind on concur_appclass_tab USING gist (i tsvector_ops (siglen='1000'), j tsvector_ops (siglen='500')); CREATEINDEX concur_appclass_ind_2 on concur_appclass_tab USING gist (k tsvector_ops (siglen='300'), j tsvector_ops);
REINDEX TABLE CONCURRENTLY concur_appclass_tab;
\d concur_appclass_tab DROPTABLE concur_appclass_tab;
-- Partitions -- Create some partitioned tables CREATETABLE concur_reindex_part (c1 int, c2 int) PARTITION BY RANGE (c1); CREATETABLE concur_reindex_part_0 PARTITION OF concur_reindex_part FORVALUESFROM (0) TO (10) PARTITION BY list (c2); CREATETABLE concur_reindex_part_0_1 PARTITION OF concur_reindex_part_0 FORVALUESIN (1); CREATETABLE concur_reindex_part_0_2 PARTITION OF concur_reindex_part_0 FORVALUESIN (2); -- This partitioned table will have no partitions. CREATETABLE concur_reindex_part_10 PARTITION OF concur_reindex_part FORVALUESFROM (10) TO (20) PARTITION BY list (c2); -- Create some partitioned indexes CREATEINDEX concur_reindex_part_index ON ONLY concur_reindex_part (c1); CREATEINDEX concur_reindex_part_index_0 ON ONLY concur_reindex_part_0 (c1); ALTERINDEX concur_reindex_part_index ATTACH PARTITION concur_reindex_part_index_0; -- This partitioned index will have no partitions. CREATEINDEX concur_reindex_part_index_10 ON ONLY concur_reindex_part_10 (c1); ALTERINDEX concur_reindex_part_index ATTACH PARTITION concur_reindex_part_index_10; CREATEINDEX concur_reindex_part_index_0_1 ON ONLY concur_reindex_part_0_1 (c1); ALTERINDEX concur_reindex_part_index_0 ATTACH PARTITION concur_reindex_part_index_0_1; CREATEINDEX concur_reindex_part_index_0_2 ON ONLY concur_reindex_part_0_2 (c1); ALTERINDEX concur_reindex_part_index_0 ATTACH PARTITION concur_reindex_part_index_0_2; SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') ORDERBY relid, level; SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') ORDERBY relid, level; -- REINDEX should preserve dependencies of partition tree. SELECT pg_describe_object(classid, objid, objsubid) as obj,
pg_describe_object(refclassid,refobjid,refobjsubid) as objref,
deptype FROM pg_depend WHERE classid = 'pg_class'::regclass AND
objid in ('concur_reindex_part'::regclass, 'concur_reindex_part_0'::regclass, 'concur_reindex_part_0_1'::regclass, 'concur_reindex_part_0_2'::regclass, 'concur_reindex_part_index'::regclass, 'concur_reindex_part_index_0'::regclass, 'concur_reindex_part_index_0_1'::regclass, 'concur_reindex_part_index_0_2'::regclass) ORDERBY1, 2;
REINDEX INDEX CONCURRENTLY concur_reindex_part_index_0_1;
REINDEX INDEX CONCURRENTLY concur_reindex_part_index_0_2; SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') ORDERBY relid, level;
REINDEX TABLE CONCURRENTLY concur_reindex_part_0_1;
REINDEX TABLE CONCURRENTLY concur_reindex_part_0_2; SELECT pg_describe_object(classid, objid, objsubid) as obj,
pg_describe_object(refclassid,refobjid,refobjsubid) as objref,
deptype FROM pg_depend WHERE classid = 'pg_class'::regclass AND
objid in ('concur_reindex_part'::regclass, 'concur_reindex_part_0'::regclass, 'concur_reindex_part_0_1'::regclass, 'concur_reindex_part_0_2'::regclass, 'concur_reindex_part_index'::regclass, 'concur_reindex_part_index_0'::regclass, 'concur_reindex_part_index_0_1'::regclass, 'concur_reindex_part_index_0_2'::regclass) ORDERBY1, 2; SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index') ORDERBY relid, level;
-- REINDEX for partitioned indexes -- REINDEX TABLE fails for partitioned indexes -- Top-most parent index
REINDEX TABLE concur_reindex_part_index; -- error
REINDEX TABLE CONCURRENTLY concur_reindex_part_index; -- error -- Partitioned index with no leaves
REINDEX TABLE concur_reindex_part_index_10; -- error
REINDEX TABLE CONCURRENTLY concur_reindex_part_index_10; -- error -- Cannot run in a transaction block
BEGIN;
REINDEX INDEX concur_reindex_part_index;
ROLLBACK; -- Helper functions to track changes of relfilenodes in a partition tree. -- Create a table tracking the relfilenode state. CREATEORREPLACE FUNCTION create_relfilenode_part(relname text, indname text)
RETURNS VOID AS
$func$
BEGIN
EXECUTE format(' CREATETABLE %I AS SELECT oid, relname, relfilenode, relkind, reltoastrelid FROM pg_class WHERE oid IN
(SELECT relid FROM pg_partition_tree(''%I''));',
relname, indname);
END
$func$ LANGUAGE plpgsql; CREATEORREPLACE FUNCTION compare_relfilenode_part(tabname text)
RETURNS TABLE (relname name, relkind "char", state text) AS
$func$
BEGIN RETURN QUERY EXECUTE
format( 'SELECT b.relname,
b.relkind, CASEWHEN a.relfilenode = b.relfilenode THEN''relfilenode is unchanged'' ELSE''relfilenode has changed'' END -- Do not join with OID here as CONCURRENTLY changes it. FROM %I b JOIN pg_class a ON b.relname = a.relname ORDERBY1;', tabname);
END
$func$ LANGUAGE plpgsql; -- Check that expected relfilenodes are changed, non-concurrent case. SELECT create_relfilenode_part('reindex_index_status', 'concur_reindex_part_index');
REINDEX INDEX concur_reindex_part_index; SELECT * FROM compare_relfilenode_part('reindex_index_status'); DROPTABLE reindex_index_status; -- concurrent case. SELECT create_relfilenode_part('reindex_index_status', 'concur_reindex_part_index');
REINDEX INDEX CONCURRENTLY concur_reindex_part_index; SELECT * FROM compare_relfilenode_part('reindex_index_status'); DROPTABLE reindex_index_status;
-- REINDEX for partitioned tables -- REINDEX INDEX fails for partitioned tables -- Top-most parent
REINDEX INDEX concur_reindex_part; -- error
REINDEX INDEX CONCURRENTLY concur_reindex_part; -- error -- Partitioned with no leaves
REINDEX INDEX concur_reindex_part_10; -- error
REINDEX INDEX CONCURRENTLY concur_reindex_part_10; -- error -- Cannot run in a transaction block
BEGIN;
REINDEX TABLE concur_reindex_part;
ROLLBACK; -- Check that expected relfilenodes are changed, non-concurrent case. -- Note that the partition tree changes of the *indexes* need to be checked. SELECT create_relfilenode_part('reindex_index_status', 'concur_reindex_part_index');
REINDEX TABLE concur_reindex_part; SELECT * FROM compare_relfilenode_part('reindex_index_status'); DROPTABLE reindex_index_status; -- concurrent case. SELECT create_relfilenode_part('reindex_index_status', 'concur_reindex_part_index');
REINDEX TABLE CONCURRENTLY concur_reindex_part; SELECT * FROM compare_relfilenode_part('reindex_index_status'); DROPTABLE reindex_index_status;
DROP FUNCTION create_relfilenode_part; DROP FUNCTION compare_relfilenode_part;
-- Cleanup of partition tree used for REINDEX test. DROPTABLE concur_reindex_part;
-- Check errors -- Cannot run inside a transaction block
BEGIN;
REINDEX TABLE CONCURRENTLY concur_reindex_tab; COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index -- These are the toast table and index of pg_database.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1262; -- no catalog toast table
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1262_index; -- no catalog toast index
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
REINDEX (CONCURRENTLY) SYSTEM postgres; -- ditto
REINDEX (CONCURRENTLY) SYSTEM; -- ditto -- Warns about catalog relations
REINDEX SCHEMA CONCURRENTLY pg_catalog; -- Not the current database
REINDEX DATABASE not_current_database;
-- Check the relation status, there should not be invalid indexes
\d concur_reindex_tab DROP MATERIALIZED VIEW concur_reindex_matview; DROPTABLE concur_reindex_tab, concur_reindex_tab2, concur_reindex_tab3;
-- Check handling of invalid indexes CREATETABLE concur_reindex_tab4 (c1 int); INSERTINTO concur_reindex_tab4 VALUES (1), (1), (2); -- This trick creates an invalid index. CREATEUNIQUEINDEX CONCURRENTLY concur_reindex_ind5 ON concur_reindex_tab4 (c1); -- Reindexing concurrently this index fails with the same failure. -- The extra index created is itself invalid, and can be dropped.
REINDEX INDEX CONCURRENTLY concur_reindex_ind5;
\d concur_reindex_tab4 DROPINDEX concur_reindex_ind5_ccnew; -- This makes the previous failure go away, so the index can become valid. DELETEFROM concur_reindex_tab4 WHERE c1 = 1; -- The invalid index is not processed when running REINDEX TABLE.
REINDEX TABLE CONCURRENTLY concur_reindex_tab4;
\d concur_reindex_tab4 -- But it is fixed with REINDEX INDEX.
REINDEX INDEX CONCURRENTLY concur_reindex_ind5;
\d concur_reindex_tab4 DROPTABLE concur_reindex_tab4;
-- Check handling of indexes with expressions and predicates. The -- definitions of the rebuilt indexes should match the original -- definitions. CREATETABLE concur_exprs_tab (c1 int , c2 boolean); INSERTINTO concur_exprs_tab (c1, c2) VALUES (1369652450, FALSE),
(414515746, TRUE),
(897778963, FALSE); CREATEUNIQUEINDEX concur_exprs_index_expr ON concur_exprs_tab ((c1::text COLLATE"C")); CREATEUNIQUEINDEX concur_exprs_index_pred ON concur_exprs_tab (c1) WHERE (c1::text > 500000000::text COLLATE"C"); CREATEUNIQUEINDEX concur_exprs_index_pred_2 ON concur_exprs_tab ((1 / c1)) WHERE ('-H') >= (c2::TEXT) COLLATE"C"; ALTERINDEX concur_exprs_index_expr ALTERCOLUMN1SET STATISTICS 100; ANALYZE concur_exprs_tab; SELECT starelid::regclass, count(*) FROM pg_statistic WHERE starelid IN ( 'concur_exprs_index_expr'::regclass, 'concur_exprs_index_pred'::regclass, 'concur_exprs_index_pred_2'::regclass) GROUPBY starelid ORDERBY starelid::regclass::text; SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass); SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass); SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass);
REINDEX TABLE CONCURRENTLY concur_exprs_tab; SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass); SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass); SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass); -- ALTER TABLE recreates the indexes, which should keep their collations. ALTERTABLE concur_exprs_tab ALTER c2 TYPE TEXT; SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass); SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass); SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass); -- Statistics should remain intact. SELECT starelid::regclass, count(*) FROM pg_statistic WHERE starelid IN ( 'concur_exprs_index_expr'::regclass, 'concur_exprs_index_pred'::regclass, 'concur_exprs_index_pred_2'::regclass) GROUPBY starelid ORDERBY starelid::regclass::text; -- attstattarget should remain intact SELECT attrelid::regclass, attnum, attstattarget FROM pg_attribute WHERE attrelid IN ( 'concur_exprs_index_expr'::regclass, 'concur_exprs_index_pred'::regclass, 'concur_exprs_index_pred_2'::regclass) ORDERBY attrelid::regclass::text, attnum; DROPTABLE concur_exprs_tab;
-- Temporary tables and on-commit actions, where CONCURRENTLY is ignored. -- ON COMMIT PRESERVE ROWS, the default. CREATE TEMP TABLE concur_temp_tab_1 (c1 int, c2 text) ONCOMMIT PRESERVE ROWS; INSERTINTO concur_temp_tab_1 VALUES (1, 'foo'), (2, 'bar'); CREATEINDEX concur_temp_ind_1 ON concur_temp_tab_1(c2);
REINDEX TABLE CONCURRENTLY concur_temp_tab_1;
REINDEX INDEX CONCURRENTLY concur_temp_ind_1; -- Still fails in transaction blocks
BEGIN;
REINDEX INDEX CONCURRENTLY concur_temp_ind_1; COMMIT; -- ON COMMIT DELETE ROWS CREATE TEMP TABLE concur_temp_tab_2 (c1 int, c2 text) ONCOMMITDELETE ROWS; CREATEINDEX concur_temp_ind_2 ON concur_temp_tab_2(c2);
REINDEX TABLE CONCURRENTLY concur_temp_tab_2;
REINDEX INDEX CONCURRENTLY concur_temp_ind_2; -- ON COMMIT DROP
BEGIN; CREATE TEMP TABLE concur_temp_tab_3 (c1 int, c2 text) ONCOMMIT PRESERVE ROWS; INSERTINTO concur_temp_tab_3 VALUES (1, 'foo'), (2, 'bar'); CREATEINDEX concur_temp_ind_3 ON concur_temp_tab_3(c2); -- Fails when running in a transaction
REINDEX INDEX CONCURRENTLY concur_temp_ind_3; COMMIT; -- REINDEX SCHEMA processes all temporary relations CREATETABLE reindex_temp_before AS SELECT oid, relname, relfilenode, relkind, reltoastrelid FROM pg_class WHERE relname IN ('concur_temp_ind_1', 'concur_temp_ind_2'); SELECT pg_my_temp_schema()::regnamespace as temp_schema_name \gset
REINDEX SCHEMA CONCURRENTLY :temp_schema_name; SELECT b.relname,
b.relkind, CASEWHEN a.relfilenode = b.relfilenode THEN'relfilenode is unchanged' ELSE'relfilenode has changed' END FROM reindex_temp_before b JOIN pg_class a ON b.oid = a.oid ORDERBY1; DROPTABLE concur_temp_tab_1, concur_temp_tab_2, reindex_temp_before;
-- No OR-clause groupings should happen, and there should be no clause -- permutations in the filtering conditions we could see in the EXPLAIN. EXPLAIN (COSTS OFF) SELECT * FROM tenk1 WHERE unique1 < 1OR hundred < 2;
-- OR clauses in the 'unique1' column are grouped, so clause permutation -- occurs. W e can see it in the 'Recheck Cond': the second clause involving -- the 'unique1' column goes just after the first one. EXPLAIN (COSTS OFF) SELECT * FROM tenk1 WHERE unique1 < 1OR unique1 < 3OR hundred < 2;
-- Check bitmap scan can consider similar OR arguments separately without -- grouping them into SAOP. CREATETABLE bitmap_split_or (a intNOTNULL, b intNOTNULL, c intNOTNULL); INSERTINTO bitmap_split_or (SELECT1, 1, i FROM generate_series(1, 1000) i); INSERTINTO bitmap_split_or (select i, 2, 2FROM generate_series(1, 1000) i);
VACUUM ANALYZE bitmap_split_or; CREATEINDEX t_b_partial_1_idx ON bitmap_split_or (b) WHERE a = 1; CREATEINDEX t_b_partial_2_idx ON bitmap_split_or (b) WHERE a = 2; EXPLAIN (COSTS OFF) SELECT * FROM bitmap_split_or WHERE (a = 1OR a = 2) AND b = 2; DROPINDEX t_b_partial_1_idx; DROPINDEX t_b_partial_2_idx; CREATEINDEX t_a_b_idx ON bitmap_split_or (a, b); CREATEINDEX t_b_c_idx ON bitmap_split_or (b, c); CREATE STATISTICS t_a_b_stat (mcv) ON a, b FROM bitmap_split_or; CREATE STATISTICS t_b_c_stat (mcv) ON b, c FROM bitmap_split_or; ANALYZE bitmap_split_or; EXPLAIN (COSTS OFF) SELECT * FROM bitmap_split_or t1, bitmap_split_or t2 WHERE t1.a = t2.b OR t1.a = 2; EXPLAIN (COSTS OFF) SELECT * FROM bitmap_split_or WHERE a = 1AND (b = 1OR b = 2) AND c = 2; DROPTABLE bitmap_split_or;
-- -- REINDEX SCHEMA --
REINDEX SCHEMA schema_to_reindex; -- failure, schema does not exist CREATESCHEMA schema_to_reindex; SET search_path = 'schema_to_reindex'; CREATETABLE table1(col1 SERIAL PRIMARYKEY); INSERTINTO table1 SELECT generate_series(1,400); CREATETABLE table2(col1 SERIAL PRIMARYKEY, col2 TEXT NOTNULL); INSERTINTO table2 SELECT generate_series(1,400), 'abc'; CREATEINDEXON table2(col2); CREATE MATERIALIZED VIEW matview ASSELECT col1 FROM table2; CREATEINDEXON matview(col1); CREATE VIEW view ASSELECT col2 FROM table2; CREATETABLE reindex_before AS SELECT oid, relname, relfilenode, relkind, reltoastrelid FROM pg_class where relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'schema_to_reindex'); INSERTINTO reindex_before SELECT oid, 'pg_toast_TABLE', relfilenode, relkind, reltoastrelid FROM pg_class WHERE oid IN
(SELECT reltoastrelid FROM reindex_before WHERE reltoastrelid > 0); INSERTINTO reindex_before SELECT oid, 'pg_toast_TABLE_index', relfilenode, relkind, reltoastrelid FROM pg_class where oid in
(select indexrelid from pg_index where indrelid in
(select reltoastrelid from reindex_before where reltoastrelid > 0));
REINDEX SCHEMA schema_to_reindex; CREATETABLE reindex_after ASSELECT oid, relname, relfilenode, relkind FROM pg_class where relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'schema_to_reindex'); SELECT b.relname,
b.relkind, CASEWHEN a.relfilenode = b.relfilenode THEN'relfilenode is unchanged' ELSE'relfilenode has changed' END FROM reindex_before b JOIN pg_class a ON b.oid = a.oid ORDERBY1;
REINDEX SCHEMA schema_to_reindex;
BEGIN;
REINDEX SCHEMA schema_to_reindex; -- failure, cannot run in a transaction
END;
-- Failure for unauthorized user CREATE ROLE regress_reindexuser NOLOGIN; SET SESSION ROLE regress_reindexuser;
REINDEX SCHEMA schema_to_reindex; -- Permission failures with toast tables and indexes (pg_authid here)
RESET ROLE; GRANTUSAGEONSCHEMA pg_toast TO regress_reindexuser; SET SESSION ROLE regress_reindexuser;
REINDEX TABLE pg_toast.pg_toast_1262;
REINDEX INDEX pg_toast.pg_toast_1262_index;
-- Clean up
RESET ROLE; REVOKEUSAGEONSCHEMA pg_toast FROM regress_reindexuser; DROP ROLE regress_reindexuser; DROPSCHEMA schema_to_reindex CASCADE;
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.13Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.