mirror of
https://github.com/postgres/postgres.git
synced 2026-01-05 23:38:41 +03:00
Commit4fb5c794eintended to add coverage of some ambuildempty methods that were not getting reached, without removing any test coverage. However, by changing a temp table to unlogged it managed to negate the intent of4c51a2d1e, which means that we didn't have reliable test coverage of ginvacuum.c anymore. As things stand, much of that file might or might not get reached depending on timing, which seems pretty undesirable. Although this is only clearly broken for the GIN test, it seems best to revert4fb5c794ealtogether and instead add bespoke test cases covering unlogged indexes for these four AMs. We don't need to do very much with them, so the extra tests are cheap. (Note that btree, hash, and bloom already have similar test cases, so they need no additional work.) We can also undodec8ad367. Since the testing deficiency that that hacked around was later fixed by2f2e24d90, let's intentionally leave an unlogged table behind to improve test coverage in the modules that use the regression database for other test purposes. (The case I used also leaves an unlogged sequence behind.) Per report from Alex Kozhemyakin. Back-patch to v15 where the faulty test came in. Discussion: https://postgr.es/m/b00c8ee096ee46cd25c183125562a1a7@postgrespro.ru
184 lines
5.5 KiB
PL/PgSQL
184 lines
5.5 KiB
PL/PgSQL
--
|
|
-- Test GIN indexes.
|
|
--
|
|
-- There are other tests to test different GIN opclasses. This is for testing
|
|
-- GIN itself.
|
|
|
|
-- Create and populate a test table with a GIN index.
|
|
create table gin_test_tbl(i int4[]) with (autovacuum_enabled = off);
|
|
create index gin_test_idx on gin_test_tbl using gin (i)
|
|
with (fastupdate = on, gin_pending_list_limit = 4096);
|
|
insert into gin_test_tbl select array[1, 2, g] from generate_series(1, 20000) g;
|
|
insert into gin_test_tbl select array[1, 3, g] from generate_series(1, 1000) g;
|
|
|
|
select gin_clean_pending_list('gin_test_idx')>10 as many; -- flush the fastupdate buffers
|
|
|
|
insert into gin_test_tbl select array[3, 1, g] from generate_series(1, 1000) g;
|
|
|
|
vacuum gin_test_tbl; -- flush the fastupdate buffers
|
|
|
|
select gin_clean_pending_list('gin_test_idx'); -- nothing to flush
|
|
|
|
-- Test vacuuming
|
|
delete from gin_test_tbl where i @> array[2];
|
|
vacuum gin_test_tbl;
|
|
|
|
-- Disable fastupdate, and do more insertions. With fastupdate enabled, most
|
|
-- insertions (by flushing the list pages) cause page splits. Without
|
|
-- fastupdate, we get more churn in the GIN data leaf pages, and exercise the
|
|
-- recompression codepaths.
|
|
alter index gin_test_idx set (fastupdate = off);
|
|
|
|
insert into gin_test_tbl select array[1, 2, g] from generate_series(1, 1000) g;
|
|
insert into gin_test_tbl select array[1, 3, g] from generate_series(1, 1000) g;
|
|
|
|
delete from gin_test_tbl where i @> array[2];
|
|
vacuum gin_test_tbl;
|
|
|
|
-- Test for "rare && frequent" searches
|
|
explain (costs off)
|
|
select count(*) from gin_test_tbl where i @> array[1, 999];
|
|
|
|
select count(*) from gin_test_tbl where i @> array[1, 999];
|
|
|
|
-- Very weak test for gin_fuzzy_search_limit
|
|
set gin_fuzzy_search_limit = 1000;
|
|
|
|
explain (costs off)
|
|
select count(*) > 0 as ok from gin_test_tbl where i @> array[1];
|
|
|
|
select count(*) > 0 as ok from gin_test_tbl where i @> array[1];
|
|
|
|
reset gin_fuzzy_search_limit;
|
|
|
|
-- Test optimization of empty queries
|
|
create temp table t_gin_test_tbl(i int4[], j int4[]);
|
|
create index on t_gin_test_tbl using gin (i, j);
|
|
insert into t_gin_test_tbl
|
|
values
|
|
(null, null),
|
|
('{}', null),
|
|
('{1}', null),
|
|
('{1,2}', null),
|
|
(null, '{}'),
|
|
(null, '{10}'),
|
|
('{1,2}', '{10}'),
|
|
('{2}', '{10}'),
|
|
('{1,3}', '{}'),
|
|
('{1,1}', '{10}');
|
|
|
|
set enable_seqscan = off;
|
|
explain (costs off)
|
|
select * from t_gin_test_tbl where array[0] <@ i;
|
|
select * from t_gin_test_tbl where array[0] <@ i;
|
|
select * from t_gin_test_tbl where array[0] <@ i and '{}'::int4[] <@ j;
|
|
|
|
explain (costs off)
|
|
select * from t_gin_test_tbl where i @> '{}';
|
|
select * from t_gin_test_tbl where i @> '{}';
|
|
|
|
create function explain_query_json(query_sql text)
|
|
returns table (explain_line json)
|
|
language plpgsql as
|
|
$$
|
|
begin
|
|
set enable_seqscan = off;
|
|
set enable_bitmapscan = on;
|
|
return query execute 'EXPLAIN (ANALYZE, FORMAT json) ' || query_sql;
|
|
end;
|
|
$$;
|
|
|
|
create function execute_text_query_index(query_sql text)
|
|
returns setof text
|
|
language plpgsql
|
|
as
|
|
$$
|
|
begin
|
|
set enable_seqscan = off;
|
|
set enable_bitmapscan = on;
|
|
return query execute query_sql;
|
|
end;
|
|
$$;
|
|
|
|
create function execute_text_query_heap(query_sql text)
|
|
returns setof text
|
|
language plpgsql
|
|
as
|
|
$$
|
|
begin
|
|
set enable_seqscan = on;
|
|
set enable_bitmapscan = off;
|
|
return query execute query_sql;
|
|
end;
|
|
$$;
|
|
|
|
-- check number of rows returned by index and removed by recheck
|
|
select
|
|
query,
|
|
js->0->'Plan'->'Plans'->0->'Actual Rows' as "return by index",
|
|
js->0->'Plan'->'Rows Removed by Index Recheck' as "removed by recheck",
|
|
(res_index = res_heap) as "match"
|
|
from
|
|
(values
|
|
($$ i @> '{}' $$),
|
|
($$ j @> '{}' $$),
|
|
($$ i @> '{}' and j @> '{}' $$),
|
|
($$ i @> '{1}' $$),
|
|
($$ i @> '{1}' and j @> '{}' $$),
|
|
($$ i @> '{1}' and i @> '{}' and j @> '{}' $$),
|
|
($$ j @> '{10}' $$),
|
|
($$ j @> '{10}' and i @> '{}' $$),
|
|
($$ j @> '{10}' and j @> '{}' and i @> '{}' $$),
|
|
($$ i @> '{1}' and j @> '{10}' $$)
|
|
) q(query),
|
|
lateral explain_query_json($$select * from t_gin_test_tbl where $$ || query) js,
|
|
lateral execute_text_query_index($$select string_agg((i, j)::text, ' ') from t_gin_test_tbl where $$ || query) res_index,
|
|
lateral execute_text_query_heap($$select string_agg((i, j)::text, ' ') from t_gin_test_tbl where $$ || query) res_heap;
|
|
|
|
reset enable_seqscan;
|
|
reset enable_bitmapscan;
|
|
|
|
-- re-purpose t_gin_test_tbl to test scans involving posting trees
|
|
insert into t_gin_test_tbl select array[1, g, g/10], array[2, g, g/10]
|
|
from generate_series(1, 20000) g;
|
|
|
|
select gin_clean_pending_list('t_gin_test_tbl_i_j_idx') is not null;
|
|
|
|
analyze t_gin_test_tbl;
|
|
|
|
set enable_seqscan = off;
|
|
set enable_bitmapscan = on;
|
|
|
|
explain (costs off)
|
|
select count(*) from t_gin_test_tbl where j @> array[50];
|
|
select count(*) from t_gin_test_tbl where j @> array[50];
|
|
explain (costs off)
|
|
select count(*) from t_gin_test_tbl where j @> array[2];
|
|
select count(*) from t_gin_test_tbl where j @> array[2];
|
|
explain (costs off)
|
|
select count(*) from t_gin_test_tbl where j @> '{}'::int[];
|
|
select count(*) from t_gin_test_tbl where j @> '{}'::int[];
|
|
|
|
-- test vacuuming of posting trees
|
|
delete from t_gin_test_tbl where j @> array[2];
|
|
vacuum t_gin_test_tbl;
|
|
|
|
select count(*) from t_gin_test_tbl where j @> array[50];
|
|
select count(*) from t_gin_test_tbl where j @> array[2];
|
|
select count(*) from t_gin_test_tbl where j @> '{}'::int[];
|
|
|
|
reset enable_seqscan;
|
|
reset enable_bitmapscan;
|
|
|
|
drop table t_gin_test_tbl;
|
|
|
|
-- test an unlogged table, mostly to get coverage of ginbuildempty
|
|
create unlogged table t_gin_test_tbl(i int4[], j int4[]);
|
|
create index on t_gin_test_tbl using gin (i, j);
|
|
insert into t_gin_test_tbl
|
|
values
|
|
(null, null),
|
|
('{}', null),
|
|
('{1}', '{2,3}');
|
|
drop table t_gin_test_tbl;
|