rearrange-regression-tests-for-more-parallelism.patch
text/x-diff
Filename: rearrange-regression-tests-for-more-parallelism.patch
Type: text/x-diff
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/pl/plpgsql/src/expected/plpgsql_trap.out | 255 | 0 |
| src/pl/plpgsql/src/Makefile | 2 | 1 |
| src/pl/plpgsql/src/sql/plpgsql_trap.sql | 175 | 0 |
| src/test/regress/expected/btree_index.out | 18 | 0 |
| src/test/regress/expected/create_index.out | 235 | 1543 |
| src/test/regress/expected/create_index_spgist.out | 1299 | 0 |
| src/test/regress/expected/index_fastpath.out | 233 | 0 |
| src/test/regress/expected/indexing.out | 0 | 233 |
| src/test/regress/expected/join_hash.out | 880 | 0 |
| src/test/regress/expected/join.out | 0 | 880 |
| src/test/regress/expected/plpgsql.out | 0 | 253 |
| src/test/regress/expected/polygon.out | 0 | 25 |
| src/test/regress/expected/rules.out | 5 | 2 |
| src/test/regress/expected/sanity_check.out | 1 | 2 |
| src/test/regress/input/constraints.source | 1 | 1 |
| src/test/regress/output/constraints.source | 1 | 1 |
| src/test/regress/parallel_schedule | 15 | 25 |
| src/test/regress/serial_schedule | 13 | 10 |
| src/test/regress/sql/btree_index.sql | 20 | 0 |
| src/test/regress/sql/create_index_spgist.sql | 415 | 0 |
| src/test/regress/sql/create_index.sql | 1 | 423 |
| src/test/regress/sql/index_fastpath.sql | 113 | 0 |
| src/test/regress/sql/indexing.sql | 0 | 114 |
| src/test/regress/sql/join_hash.sql | 469 | 0 |
| src/test/regress/sql/join.sql | 0 | 470 |
| src/test/regress/sql/plpgsql.sql | 0 | 173 |
| src/test/regress/sql/polygon.sql | 0 | 19 |
| src/test/regress/sql/rules.sql | 5 | 2 |
diff --git a/src/pl/plpgsql/src/Makefile b/src/pl/plpgsql/src/Makefile
index cc1c261..af9f6fb 100644
--- a/src/pl/plpgsql/src/Makefile
+++ b/src/pl/plpgsql/src/Makefile
@@ -27,7 +27,8 @@ DATA = plpgsql.control plpgsql--1.0.sql plpgsql--unpackaged--1.0.sql
REGRESS_OPTS = --dbname=$(PL_TESTDB)
REGRESS = plpgsql_call plpgsql_control plpgsql_domain plpgsql_record \
- plpgsql_cache plpgsql_transaction plpgsql_trigger plpgsql_varprops
+ plpgsql_cache plpgsql_transaction plpgsql_trap \
+ plpgsql_trigger plpgsql_varprops
# where to find gen_keywordlist.pl and subsidiary files
TOOLSDIR = $(top_srcdir)/src/tools
diff --git a/src/pl/plpgsql/src/expected/plpgsql_trap.out b/src/pl/plpgsql/src/expected/plpgsql_trap.out
new file mode 100644
index 0000000..881603f
--- /dev/null
+++ b/src/pl/plpgsql/src/expected/plpgsql_trap.out
@@ -0,0 +1,255 @@
+--
+-- Test error trapping
+--
+create function trap_zero_divide(int) returns int as $$
+declare x int;
+ sx smallint;
+begin
+ begin -- start a subtransaction
+ raise notice 'should see this';
+ x := 100 / $1;
+ raise notice 'should see this only if % <> 0', $1;
+ sx := $1;
+ raise notice 'should see this only if % fits in smallint', $1;
+ if $1 < 0 then
+ raise exception '% is less than zero', $1;
+ end if;
+ exception
+ when division_by_zero then
+ raise notice 'caught division_by_zero';
+ x := -1;
+ when NUMERIC_VALUE_OUT_OF_RANGE then
+ raise notice 'caught numeric_value_out_of_range';
+ x := -2;
+ end;
+ return x;
+end$$ language plpgsql;
+select trap_zero_divide(50);
+NOTICE: should see this
+NOTICE: should see this only if 50 <> 0
+NOTICE: should see this only if 50 fits in smallint
+ trap_zero_divide
+------------------
+ 2
+(1 row)
+
+select trap_zero_divide(0);
+NOTICE: should see this
+NOTICE: caught division_by_zero
+ trap_zero_divide
+------------------
+ -1
+(1 row)
+
+select trap_zero_divide(100000);
+NOTICE: should see this
+NOTICE: should see this only if 100000 <> 0
+NOTICE: caught numeric_value_out_of_range
+ trap_zero_divide
+------------------
+ -2
+(1 row)
+
+select trap_zero_divide(-100);
+NOTICE: should see this
+NOTICE: should see this only if -100 <> 0
+NOTICE: should see this only if -100 fits in smallint
+ERROR: -100 is less than zero
+CONTEXT: PL/pgSQL function trap_zero_divide(integer) line 12 at RAISE
+create table match_source as
+ select x as id, x*10 as data, x/10 as ten from generate_series(1,100) x;
+create function trap_matching_test(int) returns int as $$
+declare x int;
+ sx smallint;
+ y int;
+begin
+ begin -- start a subtransaction
+ x := 100 / $1;
+ sx := $1;
+ select into y data from match_source where id =
+ (select id from match_source b where ten = $1);
+ exception
+ when data_exception then -- category match
+ raise notice 'caught data_exception';
+ x := -1;
+ when NUMERIC_VALUE_OUT_OF_RANGE OR CARDINALITY_VIOLATION then
+ raise notice 'caught numeric_value_out_of_range or cardinality_violation';
+ x := -2;
+ end;
+ return x;
+end$$ language plpgsql;
+select trap_matching_test(50);
+ trap_matching_test
+--------------------
+ 2
+(1 row)
+
+select trap_matching_test(0);
+NOTICE: caught data_exception
+ trap_matching_test
+--------------------
+ -1
+(1 row)
+
+select trap_matching_test(100000);
+NOTICE: caught data_exception
+ trap_matching_test
+--------------------
+ -1
+(1 row)
+
+select trap_matching_test(1);
+NOTICE: caught numeric_value_out_of_range or cardinality_violation
+ trap_matching_test
+--------------------
+ -2
+(1 row)
+
+create temp table foo (f1 int);
+create function subxact_rollback_semantics() returns int as $$
+declare x int;
+begin
+ x := 1;
+ insert into foo values(x);
+ begin
+ x := x + 1;
+ insert into foo values(x);
+ raise exception 'inner';
+ exception
+ when others then
+ x := x * 10;
+ end;
+ insert into foo values(x);
+ return x;
+end$$ language plpgsql;
+select subxact_rollback_semantics();
+ subxact_rollback_semantics
+----------------------------
+ 20
+(1 row)
+
+select * from foo;
+ f1
+----
+ 1
+ 20
+(2 rows)
+
+drop table foo;
+create function trap_timeout() returns void as $$
+begin
+ declare x int;
+ begin
+ -- we assume this will take longer than 1 second:
+ select count(*) into x from generate_series(1, 1000000000000);
+ exception
+ when others then
+ raise notice 'caught others?';
+ when query_canceled then
+ raise notice 'nyeah nyeah, can''t stop me';
+ end;
+ -- Abort transaction to abandon the statement_timeout setting. Otherwise,
+ -- the next top-level statement would be vulnerable to the timeout.
+ raise exception 'end of function';
+end$$ language plpgsql;
+begin;
+set statement_timeout to 1000;
+select trap_timeout();
+NOTICE: nyeah nyeah, can't stop me
+ERROR: end of function
+CONTEXT: PL/pgSQL function trap_timeout() line 15 at RAISE
+rollback;
+-- Test for pass-by-ref values being stored in proper context
+create function test_variable_storage() returns text as $$
+declare x text;
+begin
+ x := '1234';
+ begin
+ x := x || '5678';
+ -- force error inside subtransaction SPI context
+ perform trap_zero_divide(-100);
+ exception
+ when others then
+ x := x || '9012';
+ end;
+ return x;
+end$$ language plpgsql;
+select test_variable_storage();
+NOTICE: should see this
+NOTICE: should see this only if -100 <> 0
+NOTICE: should see this only if -100 fits in smallint
+ test_variable_storage
+-----------------------
+ 123456789012
+(1 row)
+
+--
+-- test foreign key error trapping
+--
+create temp table master(f1 int primary key);
+create temp table slave(f1 int references master deferrable);
+insert into master values(1);
+insert into slave values(1);
+insert into slave values(2); -- fails
+ERROR: insert or update on table "slave" violates foreign key constraint "slave_f1_fkey"
+DETAIL: Key (f1)=(2) is not present in table "master".
+create function trap_foreign_key(int) returns int as $$
+begin
+ begin -- start a subtransaction
+ insert into slave values($1);
+ exception
+ when foreign_key_violation then
+ raise notice 'caught foreign_key_violation';
+ return 0;
+ end;
+ return 1;
+end$$ language plpgsql;
+create function trap_foreign_key_2() returns int as $$
+begin
+ begin -- start a subtransaction
+ set constraints all immediate;
+ exception
+ when foreign_key_violation then
+ raise notice 'caught foreign_key_violation';
+ return 0;
+ end;
+ return 1;
+end$$ language plpgsql;
+select trap_foreign_key(1);
+ trap_foreign_key
+------------------
+ 1
+(1 row)
+
+select trap_foreign_key(2); -- detects FK violation
+NOTICE: caught foreign_key_violation
+ trap_foreign_key
+------------------
+ 0
+(1 row)
+
+begin;
+ set constraints all deferred;
+ select trap_foreign_key(2); -- should not detect FK violation
+ trap_foreign_key
+------------------
+ 1
+(1 row)
+
+ savepoint x;
+ set constraints all immediate; -- fails
+ERROR: insert or update on table "slave" violates foreign key constraint "slave_f1_fkey"
+DETAIL: Key (f1)=(2) is not present in table "master".
+ rollback to x;
+ select trap_foreign_key_2(); -- detects FK violation
+NOTICE: caught foreign_key_violation
+ trap_foreign_key_2
+--------------------
+ 0
+(1 row)
+
+commit; -- still fails
+ERROR: insert or update on table "slave" violates foreign key constraint "slave_f1_fkey"
+DETAIL: Key (f1)=(2) is not present in table "master".
+drop function trap_foreign_key(int);
+drop function trap_foreign_key_2();
diff --git a/src/pl/plpgsql/src/sql/plpgsql_trap.sql b/src/pl/plpgsql/src/sql/plpgsql_trap.sql
new file mode 100644
index 0000000..7e75f46
--- /dev/null
+++ b/src/pl/plpgsql/src/sql/plpgsql_trap.sql
@@ -0,0 +1,175 @@
+--
+-- Test error trapping
+--
+
+create function trap_zero_divide(int) returns int as $$
+declare x int;
+ sx smallint;
+begin
+ begin -- start a subtransaction
+ raise notice 'should see this';
+ x := 100 / $1;
+ raise notice 'should see this only if % <> 0', $1;
+ sx := $1;
+ raise notice 'should see this only if % fits in smallint', $1;
+ if $1 < 0 then
+ raise exception '% is less than zero', $1;
+ end if;
+ exception
+ when division_by_zero then
+ raise notice 'caught division_by_zero';
+ x := -1;
+ when NUMERIC_VALUE_OUT_OF_RANGE then
+ raise notice 'caught numeric_value_out_of_range';
+ x := -2;
+ end;
+ return x;
+end$$ language plpgsql;
+
+select trap_zero_divide(50);
+select trap_zero_divide(0);
+select trap_zero_divide(100000);
+select trap_zero_divide(-100);
+
+create table match_source as
+ select x as id, x*10 as data, x/10 as ten from generate_series(1,100) x;
+
+create function trap_matching_test(int) returns int as $$
+declare x int;
+ sx smallint;
+ y int;
+begin
+ begin -- start a subtransaction
+ x := 100 / $1;
+ sx := $1;
+ select into y data from match_source where id =
+ (select id from match_source b where ten = $1);
+ exception
+ when data_exception then -- category match
+ raise notice 'caught data_exception';
+ x := -1;
+ when NUMERIC_VALUE_OUT_OF_RANGE OR CARDINALITY_VIOLATION then
+ raise notice 'caught numeric_value_out_of_range or cardinality_violation';
+ x := -2;
+ end;
+ return x;
+end$$ language plpgsql;
+
+select trap_matching_test(50);
+select trap_matching_test(0);
+select trap_matching_test(100000);
+select trap_matching_test(1);
+
+create temp table foo (f1 int);
+
+create function subxact_rollback_semantics() returns int as $$
+declare x int;
+begin
+ x := 1;
+ insert into foo values(x);
+ begin
+ x := x + 1;
+ insert into foo values(x);
+ raise exception 'inner';
+ exception
+ when others then
+ x := x * 10;
+ end;
+ insert into foo values(x);
+ return x;
+end$$ language plpgsql;
+
+select subxact_rollback_semantics();
+select * from foo;
+drop table foo;
+
+create function trap_timeout() returns void as $$
+begin
+ declare x int;
+ begin
+ -- we assume this will take longer than 1 second:
+ select count(*) into x from generate_series(1, 1000000000000);
+ exception
+ when others then
+ raise notice 'caught others?';
+ when query_canceled then
+ raise notice 'nyeah nyeah, can''t stop me';
+ end;
+ -- Abort transaction to abandon the statement_timeout setting. Otherwise,
+ -- the next top-level statement would be vulnerable to the timeout.
+ raise exception 'end of function';
+end$$ language plpgsql;
+
+begin;
+set statement_timeout to 1000;
+select trap_timeout();
+rollback;
+
+-- Test for pass-by-ref values being stored in proper context
+create function test_variable_storage() returns text as $$
+declare x text;
+begin
+ x := '1234';
+ begin
+ x := x || '5678';
+ -- force error inside subtransaction SPI context
+ perform trap_zero_divide(-100);
+ exception
+ when others then
+ x := x || '9012';
+ end;
+ return x;
+end$$ language plpgsql;
+
+select test_variable_storage();
+
+--
+-- test foreign key error trapping
+--
+
+create temp table master(f1 int primary key);
+
+create temp table slave(f1 int references master deferrable);
+
+insert into master values(1);
+insert into slave values(1);
+insert into slave values(2); -- fails
+
+create function trap_foreign_key(int) returns int as $$
+begin
+ begin -- start a subtransaction
+ insert into slave values($1);
+ exception
+ when foreign_key_violation then
+ raise notice 'caught foreign_key_violation';
+ return 0;
+ end;
+ return 1;
+end$$ language plpgsql;
+
+create function trap_foreign_key_2() returns int as $$
+begin
+ begin -- start a subtransaction
+ set constraints all immediate;
+ exception
+ when foreign_key_violation then
+ raise notice 'caught foreign_key_violation';
+ return 0;
+ end;
+ return 1;
+end$$ language plpgsql;
+
+select trap_foreign_key(1);
+select trap_foreign_key(2); -- detects FK violation
+
+begin;
+ set constraints all deferred;
+ select trap_foreign_key(2); -- should not detect FK violation
+ savepoint x;
+ set constraints all immediate; -- fails
+ rollback to x;
+ select trap_foreign_key_2(); -- detects FK violation
+commit; -- still fails
+
+drop function trap_foreign_key(int);
+drop function trap_foreign_key_2();
diff --git a/src/test/regress/expected/btree_index.out b/src/test/regress/expected/btree_index.out
index ff443a4..acab8e0 100644
--- a/src/test/regress/expected/btree_index.out
+++ b/src/test/regress/expected/btree_index.out
@@ -244,3 +244,21 @@ select reloptions from pg_class WHERE oid = 'btree_idx1'::regclass;
{vacuum_cleanup_index_scale_factor=70.0}
(1 row)
+--
+-- Test for multilevel page deletion
+--
+CREATE TABLE delete_test_table (a bigint, b bigint, c bigint, d bigint);
+INSERT INTO delete_test_table SELECT i, 1, 2, 3 FROM generate_series(1,80000) i;
+ALTER TABLE delete_test_table ADD PRIMARY KEY (a,b,c,d);
+-- Delete most entries, and vacuum, deleting internal pages and creating "fast
+-- root"
+DELETE FROM delete_test_table WHERE a < 79990;
+VACUUM delete_test_table;
+--
+-- Test B-tree insertion with a metapage update (XLOG_BTREE_INSERT_META
+-- WAL record type). This happens when a "fast root" page is split. This
+-- also creates coverage for nbtree FSM page recycling.
+--
+-- The vacuum above should've turned the leaf page into a fast root. We just
+-- need to insert some rows to cause the fast root page to split.
+INSERT INTO delete_test_table SELECT i, 1, 2, 3 FROM generate_series(1,1000) i;
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 388d709..f9b4768 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -68,25 +68,7 @@ CREATE TEMP TABLE gcircle_tbl AS
CREATE INDEX ggpolygonind ON gpolygon_tbl USING gist (f1);
CREATE INDEX ggcircleind ON gcircle_tbl USING gist (f1);
--
--- SP-GiST
---
-CREATE TABLE quad_point_tbl AS
- SELECT point(unique1,unique2) AS p FROM tenk1;
-INSERT INTO quad_point_tbl
- SELECT '(333.0,400.0)'::point FROM generate_series(1,1000);
-INSERT INTO quad_point_tbl VALUES (NULL), (NULL), (NULL);
-CREATE INDEX sp_quad_ind ON quad_point_tbl USING spgist (p);
-CREATE TABLE kd_point_tbl AS SELECT * FROM quad_point_tbl;
-CREATE INDEX sp_kd_ind ON kd_point_tbl USING spgist (p kd_point_ops);
-CREATE TABLE radix_text_tbl AS
- SELECT name AS t FROM road WHERE name !~ '^[0-9]';
-INSERT INTO radix_text_tbl
- SELECT 'P0123456789abcdef' FROM generate_series(1,1000);
-INSERT INTO radix_text_tbl VALUES ('P0123456789abcde');
-INSERT INTO radix_text_tbl VALUES ('P0123456789abcdefF');
-CREATE INDEX sp_radix_ind ON radix_text_tbl USING spgist (t);
---
--- Test GiST and SP-GiST indexes
+-- Test GiST indexes
--
-- get non-indexed results for comparison purposes
SET enable_seqscan = ON;
@@ -241,159 +223,6 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
(10,10)
(5 rows)
-SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
- count
--------
- 3
-(1 row)
-
-SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
- count
--------
- 11000
-(1 row)
-
-SELECT count(*) FROM quad_point_tbl;
- count
--------
- 11003
-(1 row)
-
-SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
- count
--------
- 1057
-(1 row)
-
-SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
- count
--------
- 1057
-(1 row)
-
-SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
- count
--------
- 6000
-(1 row)
-
-SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
- count
--------
- 4999
-(1 row)
-
-SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
- count
--------
- 5000
-(1 row)
-
-SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
- count
--------
- 5999
-(1 row)
-
-SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
- count
--------
- 1
-(1 row)
-
-CREATE TEMP TABLE quad_point_tbl_ord_seq1 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl;
-CREATE TEMP TABLE quad_point_tbl_ord_seq2 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-CREATE TEMP TABLE quad_point_tbl_ord_seq3 AS
-SELECT rank() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
-FROM quad_point_tbl WHERE p IS NOT NULL;
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
- count
--------
- 1000
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
- count
--------
- 1
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
- count
--------
- 1
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
- count
--------
- 272
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
- count
--------
- 272
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
- count
--------
- 273
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
- count
--------
- 273
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
- count
--------
- 1
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
- count
--------
- 2
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
- count
--------
- 50
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
- count
--------
- 50
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
- count
--------
- 48
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
- count
--------
- 48
-(1 row)
-
-SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
- count
--------
- 2
-(1 row)
-
SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10;
f1
-------------------------------------------------
@@ -515,1445 +344,326 @@ SELECT * FROM circle_tbl WHERE f1 && circle(point(1,-2), 1)
<(1,2),3>
<(1,3),5>
<(1,2),100>
- <(100,1),115>
-(4 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon;
- QUERY PLAN
-------------------------------------------------------------
- Aggregate
- -> Index Scan using ggpolygonind on gpolygon_tbl
- Index Cond: (f1 && '((1000,1000),(0,0))'::polygon)
-(3 rows)
-
-SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon;
- count
--------
- 2
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Index Scan using ggcircleind on gcircle_tbl
- Index Cond: (f1 && '<(500,500),500>'::circle)
-(3 rows)
-
-SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
- count
--------
- 2
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
- QUERY PLAN
-----------------------------------------------------
- Aggregate
- -> Index Only Scan using gpointind on point_tbl
- Index Cond: (f1 <@ '(100,100),(0,0)'::box)
-(3 rows)
-
-SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
- count
--------
- 3
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
- QUERY PLAN
-----------------------------------------------------
- Aggregate
- -> Index Only Scan using gpointind on point_tbl
- Index Cond: (f1 <@ '(100,100),(0,0)'::box)
-(3 rows)
-
-SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
- count
--------
- 3
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
- QUERY PLAN
-----------------------------------------------------------------------------------------
- Aggregate
- -> Index Only Scan using gpointind on point_tbl
- Index Cond: (f1 <@ '((0,0),(0,100),(100,100),(50,50),(100,0),(0,0))'::polygon)
-(3 rows)
-
-SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
- count
--------
- 4
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
- QUERY PLAN
-----------------------------------------------------
- Aggregate
- -> Index Only Scan using gpointind on point_tbl
- Index Cond: (f1 <@ '<(50,50),50>'::circle)
-(3 rows)
-
-SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
- count
--------
- 1
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
- QUERY PLAN
-------------------------------------------------------
- Aggregate
- -> Index Only Scan using gpointind on point_tbl p
- Index Cond: (f1 << '(0,0)'::point)
-(3 rows)
-
-SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
- count
--------
- 3
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
- QUERY PLAN
-------------------------------------------------------
- Aggregate
- -> Index Only Scan using gpointind on point_tbl p
- Index Cond: (f1 >> '(0,0)'::point)
-(3 rows)
-
-SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
- count
--------
- 3
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
- QUERY PLAN
-------------------------------------------------------
- Aggregate
- -> Index Only Scan using gpointind on point_tbl p
- Index Cond: (f1 <^ '(0,0)'::point)
-(3 rows)
-
-SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
- count
--------
- 1
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
- QUERY PLAN
-------------------------------------------------------
- Aggregate
- -> Index Only Scan using gpointind on point_tbl p
- Index Cond: (f1 >^ '(0,0)'::point)
-(3 rows)
-
-SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
- count
--------
- 4
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
- QUERY PLAN
-------------------------------------------------------
- Aggregate
- -> Index Only Scan using gpointind on point_tbl p
- Index Cond: (f1 ~= '(-5,-12)'::point)
-(3 rows)
-
-SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
- count
--------
- 1
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
- QUERY PLAN
-----------------------------------------------
- Index Only Scan using gpointind on point_tbl
- Order By: (f1 <-> '(0,1)'::point)
-(2 rows)
-
-SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
- f1
--------------------
- (10,10)
- (NaN,NaN)
- (0,0)
- (1e-300,-1e-300)
- (-3,4)
- (-10,0)
- (-5,-12)
- (5.1,34.5)
-
- (1e+300,Infinity)
-(10 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT * FROM point_tbl WHERE f1 IS NULL;
- QUERY PLAN
-----------------------------------------------
- Index Only Scan using gpointind on point_tbl
- Index Cond: (f1 IS NULL)
-(2 rows)
-
-SELECT * FROM point_tbl WHERE f1 IS NULL;
- f1
-----
-
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
- QUERY PLAN
-----------------------------------------------
- Index Only Scan using gpointind on point_tbl
- Index Cond: (f1 IS NOT NULL)
- Order By: (f1 <-> '(0,1)'::point)
-(3 rows)
-
-SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
- f1
--------------------
- (10,10)
- (NaN,NaN)
- (0,0)
- (1e-300,-1e-300)
- (-3,4)
- (-10,0)
- (-5,-12)
- (5.1,34.5)
- (1e+300,Infinity)
-(9 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
- QUERY PLAN
-------------------------------------------------
- Index Only Scan using gpointind on point_tbl
- Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
- Order By: (f1 <-> '(0,1)'::point)
-(3 rows)
-
-SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
- f1
-------------------
- (0,0)
- (1e-300,-1e-300)
- (-3,4)
- (-10,0)
- (10,10)
-(5 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
- QUERY PLAN
------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Index Cond: (p IS NULL)
-(3 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
- count
--------
- 3
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
- QUERY PLAN
------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Index Cond: (p IS NOT NULL)
-(3 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
- count
--------
- 11000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl;
- QUERY PLAN
------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
-(2 rows)
-
-SELECT count(*) FROM quad_point_tbl;
- count
--------
- 11003
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
- QUERY PLAN
------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Index Cond: (p <@ '(1000,1000),(200,200)'::box)
-(3 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
- count
--------
- 1057
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
- QUERY PLAN
------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Index Cond: (p <@ '(1000,1000),(200,200)'::box)
-(3 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
- count
--------
- 1057
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
- QUERY PLAN
------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Index Cond: (p << '(5000,4000)'::point)
-(3 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
- count
--------
- 6000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
- QUERY PLAN
------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Index Cond: (p >> '(5000,4000)'::point)
-(3 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
- count
--------
- 4999
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
- QUERY PLAN
------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Index Cond: (p <^ '(5000,4000)'::point)
-(3 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
- count
--------
- 5000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
- QUERY PLAN
------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Index Cond: (p >^ '(5000,4000)'::point)
-(3 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
- count
--------
- 5999
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
- QUERY PLAN
------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Index Cond: (p ~= '(4585,365)'::point)
-(3 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
- count
--------
- 1
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl;
- QUERY PLAN
------------------------------------------------------------
- WindowAgg
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Order By: (p <-> '(0,0)'::point)
-(3 rows)
-
-CREATE TEMP TABLE quad_point_tbl_ord_idx1 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl;
-SELECT * FROM quad_point_tbl_ord_seq1 seq FULL JOIN quad_point_tbl_ord_idx1 idx
-ON seq.n = idx.n
-AND (seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
- n | dist | p | n | dist | p
----+------+---+---+------+---
-(0 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
- QUERY PLAN
------------------------------------------------------------
- WindowAgg
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Index Cond: (p <@ '(1000,1000),(200,200)'::box)
- Order By: (p <-> '(0,0)'::point)
-(4 rows)
-
-CREATE TEMP TABLE quad_point_tbl_ord_idx2 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-SELECT * FROM quad_point_tbl_ord_seq2 seq FULL JOIN quad_point_tbl_ord_idx2 idx
-ON seq.n = idx.n
-AND (seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
- n | dist | p | n | dist | p
----+------+---+---+------+---
-(0 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
-FROM quad_point_tbl WHERE p IS NOT NULL;
- QUERY PLAN
------------------------------------------------------------
- WindowAgg
- -> Index Only Scan using sp_quad_ind on quad_point_tbl
- Index Cond: (p IS NOT NULL)
- Order By: (p <-> '(333,400)'::point)
-(4 rows)
-
-CREATE TEMP TABLE quad_point_tbl_ord_idx3 AS
-SELECT rank() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
-FROM quad_point_tbl WHERE p IS NOT NULL;
-SELECT * FROM quad_point_tbl_ord_seq3 seq FULL JOIN quad_point_tbl_ord_idx3 idx
-ON seq.n = idx.n
-AND (seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
- n | dist | p | n | dist | p
----+------+---+---+------+---
-(0 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
- QUERY PLAN
----------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_kd_ind on kd_point_tbl
- Index Cond: (p <@ '(1000,1000),(200,200)'::box)
-(3 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
- count
--------
- 1057
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
- QUERY PLAN
----------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_kd_ind on kd_point_tbl
- Index Cond: (p <@ '(1000,1000),(200,200)'::box)
-(3 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
- count
--------
- 1057
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_kd_ind on kd_point_tbl
- Index Cond: (p << '(5000,4000)'::point)
-(3 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
- count
--------
- 6000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_kd_ind on kd_point_tbl
- Index Cond: (p >> '(5000,4000)'::point)
-(3 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
- count
--------
- 4999
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_kd_ind on kd_point_tbl
- Index Cond: (p <^ '(5000,4000)'::point)
-(3 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
- count
--------
- 5000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_kd_ind on kd_point_tbl
- Index Cond: (p >^ '(5000,4000)'::point)
-(3 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
- count
--------
- 5999
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_kd_ind on kd_point_tbl
- Index Cond: (p ~= '(4585,365)'::point)
-(3 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
- count
--------
- 1
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM kd_point_tbl;
- QUERY PLAN
--------------------------------------------------------
- WindowAgg
- -> Index Only Scan using sp_kd_ind on kd_point_tbl
- Order By: (p <-> '(0,0)'::point)
-(3 rows)
-
-CREATE TEMP TABLE kd_point_tbl_ord_idx1 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM kd_point_tbl;
-SELECT * FROM quad_point_tbl_ord_seq1 seq FULL JOIN kd_point_tbl_ord_idx1 idx
-ON seq.n = idx.n AND
-(seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
- n | dist | p | n | dist | p
----+------+---+---+------+---
-(0 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
- QUERY PLAN
----------------------------------------------------------
- WindowAgg
- -> Index Only Scan using sp_kd_ind on kd_point_tbl
- Index Cond: (p <@ '(1000,1000),(200,200)'::box)
- Order By: (p <-> '(0,0)'::point)
-(4 rows)
-
-CREATE TEMP TABLE kd_point_tbl_ord_idx2 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-SELECT * FROM quad_point_tbl_ord_seq2 seq FULL JOIN kd_point_tbl_ord_idx2 idx
-ON seq.n = idx.n AND
-(seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
- n | dist | p | n | dist | p
----+------+---+---+------+---
-(0 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
-FROM kd_point_tbl WHERE p IS NOT NULL;
- QUERY PLAN
--------------------------------------------------------
- WindowAgg
- -> Index Only Scan using sp_kd_ind on kd_point_tbl
- Index Cond: (p IS NOT NULL)
- Order By: (p <-> '(333,400)'::point)
-(4 rows)
-
-CREATE TEMP TABLE kd_point_tbl_ord_idx3 AS
-SELECT rank() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
-FROM kd_point_tbl WHERE p IS NOT NULL;
-SELECT * FROM quad_point_tbl_ord_seq3 seq FULL JOIN kd_point_tbl_ord_idx3 idx
-ON seq.n = idx.n AND
-(seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
- n | dist | p | n | dist | p
----+------+---+---+------+---
-(0 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
- QUERY PLAN
-------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t = 'P0123456789abcdef'::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
- count
--------
- 1000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
- QUERY PLAN
-------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t = 'P0123456789abcde'::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
- count
--------
- 1
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
- QUERY PLAN
-------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t = 'P0123456789abcdefF'::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
- count
--------
- 1
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
- QUERY PLAN
-----------------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t < 'Aztec Ct '::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
- count
--------
- 272
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
- QUERY PLAN
-------------------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t ~<~ 'Aztec Ct '::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
- count
--------
- 272
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
- QUERY PLAN
------------------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t <= 'Aztec Ct '::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
- count
--------
- 273
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
- QUERY PLAN
--------------------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t ~<=~ 'Aztec Ct '::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
- count
--------
- 273
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
- QUERY PLAN
-----------------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t = 'Aztec Ct '::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
- count
--------
- 1
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
- QUERY PLAN
-----------------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t = 'Worth St '::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
- count
--------
- 2
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
- QUERY PLAN
------------------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t >= 'Worth St '::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
- count
--------
- 50
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
- QUERY PLAN
--------------------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t ~>=~ 'Worth St '::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
- count
--------
- 50
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
- QUERY PLAN
-----------------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t > 'Worth St '::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
- count
--------
- 48
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
- QUERY PLAN
-------------------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t ~>~ 'Worth St '::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
- count
--------
- 48
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
- QUERY PLAN
-------------------------------------------------------------
- Aggregate
- -> Index Only Scan using sp_radix_ind on radix_text_tbl
- Index Cond: (t ^@ 'Worth'::text)
-(3 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
- count
--------
- 2
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10;
- QUERY PLAN
------------------------------------------------------
- Limit
- -> Index Scan using ggpolygonind on gpolygon_tbl
- Order By: (f1 <-> '(0,0)'::point)
-(3 rows)
-
-SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10;
- f1
--------------------------------------------------
- ((240,359),(240,455),(337,455),(337,359))
- ((662,163),(662,187),(759,187),(759,163))
- ((1000,0),(0,1000))
- ((0,1000),(1000,1000))
- ((1346,344),(1346,403),(1444,403),(1444,344))
- ((278,1409),(278,1457),(369,1457),(369,1409))
- ((907,1156),(907,1201),(948,1201),(948,1156))
- ((1517,971),(1517,1043),(1594,1043),(1594,971))
- ((175,1820),(175,1850),(259,1850),(259,1820))
- ((2424,81),(2424,160),(2424,160),(2424,81))
-(10 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10;
- QUERY PLAN
----------------------------------------------------
- Limit
- -> Index Scan using ggcircleind on gcircle_tbl
- Order By: (f1 <-> '(200,300)'::point)
-(3 rows)
-
-SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10;
- circle_center | radius
-----------------+--------
- (288.5,407) | 68
- (710.5,175) | 50
- (323.5,1433) | 51
- (927.5,1178.5) | 30
- (1395,373.5) | 57
- (1555.5,1007) | 53
- (217,1835) | 45
- (489,2421.5) | 22
- (2424,120.5) | 40
- (751.5,2655) | 20
-(10 rows)
-
--- 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 ORDER BY f1 <-> '0,1';
- QUERY PLAN
-------------------------------------------------------------
- Sort
- Sort Key: ((f1 <-> '(0,1)'::point))
- -> Bitmap Heap Scan on point_tbl
- Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
- -> Bitmap Index Scan on gpointind
- Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
-(6 rows)
-
-SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
- f1
-------------------
- (0,0)
- (1e-300,-1e-300)
- (-3,4)
- (-10,0)
- (10,10)
-(5 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
- QUERY PLAN
-----------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on quad_point_tbl
- Recheck Cond: (p IS NULL)
- -> Bitmap Index Scan on sp_quad_ind
- Index Cond: (p IS NULL)
-(5 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
- count
--------
- 3
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
- QUERY PLAN
-----------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on quad_point_tbl
- Recheck Cond: (p IS NOT NULL)
- -> Bitmap Index Scan on sp_quad_ind
- Index Cond: (p IS NOT NULL)
-(5 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
- count
--------
- 11000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl;
- QUERY PLAN
-----------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on quad_point_tbl
- -> Bitmap Index Scan on sp_quad_ind
-(3 rows)
-
-SELECT count(*) FROM quad_point_tbl;
- count
--------
- 11003
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
- QUERY PLAN
----------------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on quad_point_tbl
- Recheck Cond: (p <@ '(1000,1000),(200,200)'::box)
- -> Bitmap Index Scan on sp_quad_ind
- Index Cond: (p <@ '(1000,1000),(200,200)'::box)
-(5 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
- count
--------
- 1057
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
- QUERY PLAN
----------------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on quad_point_tbl
- Recheck Cond: ('(1000,1000),(200,200)'::box @> p)
- -> Bitmap Index Scan on sp_quad_ind
- Index Cond: (p <@ '(1000,1000),(200,200)'::box)
-(5 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
- count
--------
- 1057
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on quad_point_tbl
- Recheck Cond: (p << '(5000,4000)'::point)
- -> Bitmap Index Scan on sp_quad_ind
- Index Cond: (p << '(5000,4000)'::point)
-(5 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
- count
--------
- 6000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on quad_point_tbl
- Recheck Cond: (p >> '(5000,4000)'::point)
- -> Bitmap Index Scan on sp_quad_ind
- Index Cond: (p >> '(5000,4000)'::point)
-(5 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
- count
--------
- 4999
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on quad_point_tbl
- Recheck Cond: (p <^ '(5000,4000)'::point)
- -> Bitmap Index Scan on sp_quad_ind
- Index Cond: (p <^ '(5000,4000)'::point)
-(5 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
- count
--------
- 5000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on quad_point_tbl
- Recheck Cond: (p >^ '(5000,4000)'::point)
- -> Bitmap Index Scan on sp_quad_ind
- Index Cond: (p >^ '(5000,4000)'::point)
-(5 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
- count
--------
- 5999
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
- QUERY PLAN
-------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on quad_point_tbl
- Recheck Cond: (p ~= '(4585,365)'::point)
- -> Bitmap Index Scan on sp_quad_ind
- Index Cond: (p ~= '(4585,365)'::point)
-(5 rows)
-
-SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
- count
--------
- 1
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
- QUERY PLAN
----------------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on kd_point_tbl
- Recheck Cond: (p <@ '(1000,1000),(200,200)'::box)
- -> Bitmap Index Scan on sp_kd_ind
- Index Cond: (p <@ '(1000,1000),(200,200)'::box)
-(5 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
- count
--------
- 1057
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
- QUERY PLAN
----------------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on kd_point_tbl
- Recheck Cond: ('(1000,1000),(200,200)'::box @> p)
- -> Bitmap Index Scan on sp_kd_ind
- Index Cond: (p <@ '(1000,1000),(200,200)'::box)
-(5 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
- count
--------
- 1057
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on kd_point_tbl
- Recheck Cond: (p << '(5000,4000)'::point)
- -> Bitmap Index Scan on sp_kd_ind
- Index Cond: (p << '(5000,4000)'::point)
-(5 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
- count
--------
- 6000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on kd_point_tbl
- Recheck Cond: (p >> '(5000,4000)'::point)
- -> Bitmap Index Scan on sp_kd_ind
- Index Cond: (p >> '(5000,4000)'::point)
-(5 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
- count
--------
- 4999
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on kd_point_tbl
- Recheck Cond: (p <^ '(5000,4000)'::point)
- -> Bitmap Index Scan on sp_kd_ind
- Index Cond: (p <^ '(5000,4000)'::point)
-(5 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
- count
--------
- 5000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
- QUERY PLAN
--------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on kd_point_tbl
- Recheck Cond: (p >^ '(5000,4000)'::point)
- -> Bitmap Index Scan on sp_kd_ind
- Index Cond: (p >^ '(5000,4000)'::point)
-(5 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
- count
--------
- 5999
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
- QUERY PLAN
-------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on kd_point_tbl
- Recheck Cond: (p ~= '(4585,365)'::point)
- -> Bitmap Index Scan on sp_kd_ind
- Index Cond: (p ~= '(4585,365)'::point)
-(5 rows)
-
-SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
- count
--------
- 1
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
- QUERY PLAN
------------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t = 'P0123456789abcdef'::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t = 'P0123456789abcdef'::text)
-(5 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
- count
--------
- 1000
-(1 row)
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
- QUERY PLAN
-----------------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t = 'P0123456789abcde'::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t = 'P0123456789abcde'::text)
-(5 rows)
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
- count
--------
- 1
-(1 row)
+ <(100,1),115>
+(4 rows)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon;
QUERY PLAN
------------------------------------------------------------
Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t = 'P0123456789abcdefF'::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t = 'P0123456789abcdefF'::text)
-(5 rows)
+ -> Index Scan using ggpolygonind on gpolygon_tbl
+ Index Cond: (f1 && '((1000,1000),(0,0))'::polygon)
+(3 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon;
count
-------
- 1
+ 2
(1 row)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
- QUERY PLAN
-----------------------------------------------------------------------------
+SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
+ QUERY PLAN
+-------------------------------------------------------
Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t < 'Aztec Ct '::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t < 'Aztec Ct '::text)
-(5 rows)
+ -> Index Scan using ggcircleind on gcircle_tbl
+ Index Cond: (f1 && '<(500,500),500>'::circle)
+(3 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
+SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
count
-------
- 272
+ 2
(1 row)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
- QUERY PLAN
-------------------------------------------------------------------------------
+SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
+ QUERY PLAN
+----------------------------------------------------
Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t ~<~ 'Aztec Ct '::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t ~<~ 'Aztec Ct '::text)
-(5 rows)
+ -> Index Only Scan using gpointind on point_tbl
+ Index Cond: (f1 <@ '(100,100),(0,0)'::box)
+(3 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
+SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
count
-------
- 272
+ 3
(1 row)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
- QUERY PLAN
------------------------------------------------------------------------------
+SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
+ QUERY PLAN
+----------------------------------------------------
Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t <= 'Aztec Ct '::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t <= 'Aztec Ct '::text)
-(5 rows)
+ -> Index Only Scan using gpointind on point_tbl
+ Index Cond: (f1 <@ '(100,100),(0,0)'::box)
+(3 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
+SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
count
-------
- 273
+ 3
(1 row)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
- QUERY PLAN
--------------------------------------------------------------------------------
+SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
+ QUERY PLAN
+----------------------------------------------------------------------------------------
Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t ~<=~ 'Aztec Ct '::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t ~<=~ 'Aztec Ct '::text)
-(5 rows)
+ -> Index Only Scan using gpointind on point_tbl
+ Index Cond: (f1 <@ '((0,0),(0,100),(100,100),(50,50),(100,0),(0,0))'::polygon)
+(3 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
+SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
count
-------
- 273
+ 4
(1 row)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
- QUERY PLAN
-----------------------------------------------------------------------------
+SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
+ QUERY PLAN
+----------------------------------------------------
Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t = 'Aztec Ct '::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t = 'Aztec Ct '::text)
-(5 rows)
+ -> Index Only Scan using gpointind on point_tbl
+ Index Cond: (f1 <@ '<(50,50),50>'::circle)
+(3 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
+SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
count
-------
1
(1 row)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
- QUERY PLAN
-----------------------------------------------------------------------------
+SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
+ QUERY PLAN
+------------------------------------------------------
Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t = 'Worth St '::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t = 'Worth St '::text)
-(5 rows)
+ -> Index Only Scan using gpointind on point_tbl p
+ Index Cond: (f1 << '(0,0)'::point)
+(3 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
+SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
count
-------
- 2
+ 3
(1 row)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
- QUERY PLAN
------------------------------------------------------------------------------
+SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
+ QUERY PLAN
+------------------------------------------------------
Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t >= 'Worth St '::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t >= 'Worth St '::text)
-(5 rows)
+ -> Index Only Scan using gpointind on point_tbl p
+ Index Cond: (f1 >> '(0,0)'::point)
+(3 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
+SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
count
-------
- 50
+ 3
(1 row)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
- QUERY PLAN
--------------------------------------------------------------------------------
+SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
+ QUERY PLAN
+------------------------------------------------------
Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t ~>=~ 'Worth St '::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t ~>=~ 'Worth St '::text)
-(5 rows)
+ -> Index Only Scan using gpointind on point_tbl p
+ Index Cond: (f1 <^ '(0,0)'::point)
+(3 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
+SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
count
-------
- 50
+ 1
(1 row)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
- QUERY PLAN
-----------------------------------------------------------------------------
+SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
+ QUERY PLAN
+------------------------------------------------------
Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t > 'Worth St '::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t > 'Worth St '::text)
-(5 rows)
+ -> Index Only Scan using gpointind on point_tbl p
+ Index Cond: (f1 >^ '(0,0)'::point)
+(3 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
+SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
count
-------
- 48
+ 4
(1 row)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
- QUERY PLAN
-------------------------------------------------------------------------------
+SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
+ QUERY PLAN
+------------------------------------------------------
Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t ~>~ 'Worth St '::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t ~>~ 'Worth St '::text)
-(5 rows)
+ -> Index Only Scan using gpointind on point_tbl p
+ Index Cond: (f1 ~= '(-5,-12)'::point)
+(3 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
+SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
count
-------
- 48
+ 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
+ QUERY PLAN
+----------------------------------------------
+ Index Only Scan using gpointind on point_tbl
+ Order By: (f1 <-> '(0,1)'::point)
+(2 rows)
+
+SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
+ f1
+-------------------
+ (10,10)
+ (NaN,NaN)
+ (0,0)
+ (1e-300,-1e-300)
+ (-3,4)
+ (-10,0)
+ (-5,-12)
+ (5.1,34.5)
+
+ (1e+300,Infinity)
+(10 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM point_tbl WHERE f1 IS NULL;
+ QUERY PLAN
+----------------------------------------------
+ Index Only Scan using gpointind on point_tbl
+ Index Cond: (f1 IS NULL)
+(2 rows)
+
+SELECT * FROM point_tbl WHERE f1 IS NULL;
+ f1
+----
+
(1 row)
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
+SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
+ QUERY PLAN
+----------------------------------------------
+ Index Only Scan using gpointind on point_tbl
+ Index Cond: (f1 IS NOT NULL)
+ Order By: (f1 <-> '(0,1)'::point)
+(3 rows)
+
+SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
+ f1
+-------------------
+ (10,10)
+ (NaN,NaN)
+ (0,0)
+ (1e-300,-1e-300)
+ (-3,4)
+ (-10,0)
+ (-5,-12)
+ (5.1,34.5)
+ (1e+300,Infinity)
+(9 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
QUERY PLAN
------------------------------------------------
- Aggregate
- -> Bitmap Heap Scan on radix_text_tbl
- Recheck Cond: (t ^@ 'Worth'::text)
- -> Bitmap Index Scan on sp_radix_ind
- Index Cond: (t ^@ 'Worth'::text)
+ Index Only Scan using gpointind on point_tbl
+ Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
+ Order By: (f1 <-> '(0,1)'::point)
+(3 rows)
+
+SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+ f1
+------------------
+ (0,0)
+ (1e-300,-1e-300)
+ (-3,4)
+ (-10,0)
+ (10,10)
(5 rows)
-SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
- count
--------
- 2
-(1 row)
+EXPLAIN (COSTS OFF)
+SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10;
+ QUERY PLAN
+-----------------------------------------------------
+ Limit
+ -> Index Scan using ggpolygonind on gpolygon_tbl
+ Order By: (f1 <-> '(0,0)'::point)
+(3 rows)
+
+SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10;
+ f1
+-------------------------------------------------
+ ((240,359),(240,455),(337,455),(337,359))
+ ((662,163),(662,187),(759,187),(759,163))
+ ((1000,0),(0,1000))
+ ((0,1000),(1000,1000))
+ ((1346,344),(1346,403),(1444,403),(1444,344))
+ ((278,1409),(278,1457),(369,1457),(369,1409))
+ ((907,1156),(907,1201),(948,1201),(948,1156))
+ ((1517,971),(1517,1043),(1594,1043),(1594,971))
+ ((175,1820),(175,1850),(259,1850),(259,1820))
+ ((2424,81),(2424,160),(2424,160),(2424,81))
+(10 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10;
+ QUERY PLAN
+---------------------------------------------------
+ Limit
+ -> Index Scan using ggcircleind on gcircle_tbl
+ Order By: (f1 <-> '(200,300)'::point)
+(3 rows)
+
+SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10;
+ circle_center | radius
+----------------+--------
+ (288.5,407) | 68
+ (710.5,175) | 50
+ (323.5,1433) | 51
+ (927.5,1178.5) | 30
+ (1395,373.5) | 57
+ (1555.5,1007) | 53
+ (217,1835) | 45
+ (489,2421.5) | 22
+ (2424,120.5) | 40
+ (751.5,2655) | 20
+(10 rows)
+
+-- 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 ORDER BY f1 <-> '0,1';
+ QUERY PLAN
+------------------------------------------------------------
+ Sort
+ Sort Key: ((f1 <-> '(0,1)'::point))
+ -> Bitmap Heap Scan on point_tbl
+ Recheck Cond: (f1 <@ '(10,10),(-10,-10)'::box)
+ -> Bitmap Index Scan on gpointind
+ Index Cond: (f1 <@ '(10,10),(-10,-10)'::box)
+(6 rows)
+
+SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
+ f1
+------------------
+ (0,0)
+ (1e-300,-1e-300)
+ (-3,4)
+ (-10,0)
+ (10,10)
+(5 rows)
RESET enable_seqscan;
RESET enable_indexscan;
@@ -3220,24 +1930,6 @@ explain (costs off)
(3 rows)
--
--- Test for multilevel page deletion
---
-CREATE TABLE delete_test_table (a bigint, b bigint, c bigint, d bigint);
-INSERT INTO delete_test_table SELECT i, 1, 2, 3 FROM generate_series(1,80000) i;
-ALTER TABLE delete_test_table ADD PRIMARY KEY (a,b,c,d);
--- Delete most entries, and vacuum, deleting internal pages and creating "fast
--- root"
-DELETE FROM delete_test_table WHERE a < 79990;
-VACUUM delete_test_table;
---
--- Test B-tree insertion with a metapage update (XLOG_BTREE_INSERT_META
--- WAL record type). This happens when a "fast root" page is split. This
--- also creates coverage for nbtree FSM page recycling.
---
--- The vacuum above should've turned the leaf page into a fast root. We just
--- need to insert some rows to cause the fast root page to split.
-INSERT INTO delete_test_table SELECT i, 1, 2, 3 FROM generate_series(1,1000) i;
---
-- REINDEX (VERBOSE)
--
CREATE TABLE reindex_verbose(id integer primary key);
diff --git a/src/test/regress/expected/create_index_spgist.out b/src/test/regress/expected/create_index_spgist.out
new file mode 100644
index 0000000..81b4a67
--- /dev/null
+++ b/src/test/regress/expected/create_index_spgist.out
@@ -0,0 +1,1299 @@
+--
+-- SP-GiST index tests
+--
+CREATE TABLE quad_point_tbl AS
+ SELECT point(unique1,unique2) AS p FROM tenk1;
+INSERT INTO quad_point_tbl
+ SELECT '(333.0,400.0)'::point FROM generate_series(1,1000);
+INSERT INTO quad_point_tbl VALUES (NULL), (NULL), (NULL);
+CREATE INDEX sp_quad_ind ON quad_point_tbl USING spgist (p);
+CREATE TABLE kd_point_tbl AS SELECT * FROM quad_point_tbl;
+CREATE INDEX sp_kd_ind ON kd_point_tbl USING spgist (p kd_point_ops);
+CREATE TABLE radix_text_tbl AS
+ SELECT name AS t FROM road WHERE name !~ '^[0-9]';
+INSERT INTO radix_text_tbl
+ SELECT 'P0123456789abcdef' FROM generate_series(1,1000);
+INSERT INTO radix_text_tbl VALUES ('P0123456789abcde');
+INSERT INTO radix_text_tbl VALUES ('P0123456789abcdefF');
+CREATE INDEX sp_radix_ind ON radix_text_tbl USING spgist (t);
+-- get non-indexed results for comparison purposes
+SET enable_seqscan = ON;
+SET enable_indexscan = OFF;
+SET enable_bitmapscan = OFF;
+SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
+ count
+-------
+ 3
+(1 row)
+
+SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
+ count
+-------
+ 11000
+(1 row)
+
+SELECT count(*) FROM quad_point_tbl;
+ count
+-------
+ 11003
+(1 row)
+
+SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+ count
+-------
+ 1057
+(1 row)
+
+SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+ count
+-------
+ 1057
+(1 row)
+
+SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
+ count
+-------
+ 6000
+(1 row)
+
+SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
+ count
+-------
+ 4999
+(1 row)
+
+SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
+ count
+-------
+ 5000
+(1 row)
+
+SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
+ count
+-------
+ 5999
+(1 row)
+
+SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
+ count
+-------
+ 1
+(1 row)
+
+CREATE TEMP TABLE quad_point_tbl_ord_seq1 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl;
+CREATE TEMP TABLE quad_point_tbl_ord_seq2 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+CREATE TEMP TABLE quad_point_tbl_ord_seq3 AS
+SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
+FROM quad_point_tbl WHERE p IS NOT NULL;
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
+ count
+-------
+ 1000
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
+ count
+-------
+ 1
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+ count
+-------
+ 1
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
+ count
+-------
+ 272
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
+ count
+-------
+ 272
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
+ count
+-------
+ 273
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
+ count
+-------
+ 273
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
+ count
+-------
+ 1
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
+ count
+-------
+ 2
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
+ count
+-------
+ 50
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
+ count
+-------
+ 50
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
+ count
+-------
+ 48
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
+ count
+-------
+ 48
+(1 row)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
+ count
+-------
+ 2
+(1 row)
+
+-- Now check the results from plain indexscan
+SET enable_seqscan = OFF;
+SET enable_indexscan = ON;
+SET enable_bitmapscan = OFF;
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
+ QUERY PLAN
+-----------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Index Cond: (p IS NULL)
+(3 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
+ count
+-------
+ 3
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
+ QUERY PLAN
+-----------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Index Cond: (p IS NOT NULL)
+(3 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
+ count
+-------
+ 11000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl;
+ QUERY PLAN
+-----------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+(2 rows)
+
+SELECT count(*) FROM quad_point_tbl;
+ count
+-------
+ 11003
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+ QUERY PLAN
+-----------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Index Cond: (p <@ '(1000,1000),(200,200)'::box)
+(3 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+ count
+-------
+ 1057
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+ QUERY PLAN
+-----------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Index Cond: (p <@ '(1000,1000),(200,200)'::box)
+(3 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+ count
+-------
+ 1057
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
+ QUERY PLAN
+-----------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Index Cond: (p << '(5000,4000)'::point)
+(3 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
+ count
+-------
+ 6000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
+ QUERY PLAN
+-----------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Index Cond: (p >> '(5000,4000)'::point)
+(3 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
+ count
+-------
+ 4999
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
+ QUERY PLAN
+-----------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Index Cond: (p <^ '(5000,4000)'::point)
+(3 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
+ count
+-------
+ 5000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
+ QUERY PLAN
+-----------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Index Cond: (p >^ '(5000,4000)'::point)
+(3 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
+ count
+-------
+ 5999
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
+ QUERY PLAN
+-----------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Index Cond: (p ~= '(4585,365)'::point)
+(3 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl;
+ QUERY PLAN
+-----------------------------------------------------------
+ WindowAgg
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Order By: (p <-> '(0,0)'::point)
+(3 rows)
+
+CREATE TEMP TABLE quad_point_tbl_ord_idx1 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl;
+SELECT * FROM quad_point_tbl_ord_seq1 seq FULL JOIN quad_point_tbl_ord_idx1 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+ n | dist | p | n | dist | p
+---+------+---+---+------+---
+(0 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+ QUERY PLAN
+-----------------------------------------------------------
+ WindowAgg
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Index Cond: (p <@ '(1000,1000),(200,200)'::box)
+ Order By: (p <-> '(0,0)'::point)
+(4 rows)
+
+CREATE TEMP TABLE quad_point_tbl_ord_idx2 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+SELECT * FROM quad_point_tbl_ord_seq2 seq FULL JOIN quad_point_tbl_ord_idx2 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+ n | dist | p | n | dist | p
+---+------+---+---+------+---
+(0 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
+FROM quad_point_tbl WHERE p IS NOT NULL;
+ QUERY PLAN
+-----------------------------------------------------------
+ WindowAgg
+ -> Index Only Scan using sp_quad_ind on quad_point_tbl
+ Index Cond: (p IS NOT NULL)
+ Order By: (p <-> '(333,400)'::point)
+(4 rows)
+
+CREATE TEMP TABLE quad_point_tbl_ord_idx3 AS
+SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
+FROM quad_point_tbl WHERE p IS NOT NULL;
+SELECT * FROM quad_point_tbl_ord_seq3 seq FULL JOIN quad_point_tbl_ord_idx3 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+ n | dist | p | n | dist | p
+---+------+---+---+------+---
+(0 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+ QUERY PLAN
+---------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_kd_ind on kd_point_tbl
+ Index Cond: (p <@ '(1000,1000),(200,200)'::box)
+(3 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+ count
+-------
+ 1057
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+ QUERY PLAN
+---------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_kd_ind on kd_point_tbl
+ Index Cond: (p <@ '(1000,1000),(200,200)'::box)
+(3 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+ count
+-------
+ 1057
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_kd_ind on kd_point_tbl
+ Index Cond: (p << '(5000,4000)'::point)
+(3 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
+ count
+-------
+ 6000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_kd_ind on kd_point_tbl
+ Index Cond: (p >> '(5000,4000)'::point)
+(3 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
+ count
+-------
+ 4999
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_kd_ind on kd_point_tbl
+ Index Cond: (p <^ '(5000,4000)'::point)
+(3 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
+ count
+-------
+ 5000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_kd_ind on kd_point_tbl
+ Index Cond: (p >^ '(5000,4000)'::point)
+(3 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
+ count
+-------
+ 5999
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_kd_ind on kd_point_tbl
+ Index Cond: (p ~= '(4585,365)'::point)
+(3 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM kd_point_tbl;
+ QUERY PLAN
+-------------------------------------------------------
+ WindowAgg
+ -> Index Only Scan using sp_kd_ind on kd_point_tbl
+ Order By: (p <-> '(0,0)'::point)
+(3 rows)
+
+CREATE TEMP TABLE kd_point_tbl_ord_idx1 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM kd_point_tbl;
+SELECT * FROM quad_point_tbl_ord_seq1 seq FULL JOIN kd_point_tbl_ord_idx1 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+ n | dist | p | n | dist | p
+---+------+---+---+------+---
+(0 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+ QUERY PLAN
+---------------------------------------------------------
+ WindowAgg
+ -> Index Only Scan using sp_kd_ind on kd_point_tbl
+ Index Cond: (p <@ '(1000,1000),(200,200)'::box)
+ Order By: (p <-> '(0,0)'::point)
+(4 rows)
+
+CREATE TEMP TABLE kd_point_tbl_ord_idx2 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+SELECT * FROM quad_point_tbl_ord_seq2 seq FULL JOIN kd_point_tbl_ord_idx2 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+ n | dist | p | n | dist | p
+---+------+---+---+------+---
+(0 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
+FROM kd_point_tbl WHERE p IS NOT NULL;
+ QUERY PLAN
+-------------------------------------------------------
+ WindowAgg
+ -> Index Only Scan using sp_kd_ind on kd_point_tbl
+ Index Cond: (p IS NOT NULL)
+ Order By: (p <-> '(333,400)'::point)
+(4 rows)
+
+CREATE TEMP TABLE kd_point_tbl_ord_idx3 AS
+SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
+FROM kd_point_tbl WHERE p IS NOT NULL;
+SELECT * FROM quad_point_tbl_ord_seq3 seq FULL JOIN kd_point_tbl_ord_idx3 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+ n | dist | p | n | dist | p
+---+------+---+---+------+---
+(0 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
+ QUERY PLAN
+------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t = 'P0123456789abcdef'::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
+ count
+-------
+ 1000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
+ QUERY PLAN
+------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t = 'P0123456789abcde'::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+ QUERY PLAN
+------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t = 'P0123456789abcdefF'::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
+ QUERY PLAN
+----------------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t < 'Aztec Ct '::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
+ count
+-------
+ 272
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
+ QUERY PLAN
+------------------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t ~<~ 'Aztec Ct '::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
+ count
+-------
+ 272
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
+ QUERY PLAN
+-----------------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t <= 'Aztec Ct '::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
+ count
+-------
+ 273
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t ~<=~ 'Aztec Ct '::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
+ count
+-------
+ 273
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
+ QUERY PLAN
+----------------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t = 'Aztec Ct '::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
+ QUERY PLAN
+----------------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t = 'Worth St '::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
+ count
+-------
+ 2
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
+ QUERY PLAN
+-----------------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t >= 'Worth St '::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
+ count
+-------
+ 50
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t ~>=~ 'Worth St '::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
+ count
+-------
+ 50
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
+ QUERY PLAN
+----------------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t > 'Worth St '::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
+ count
+-------
+ 48
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
+ QUERY PLAN
+------------------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t ~>~ 'Worth St '::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
+ count
+-------
+ 48
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
+ QUERY PLAN
+------------------------------------------------------------
+ Aggregate
+ -> Index Only Scan using sp_radix_ind on radix_text_tbl
+ Index Cond: (t ^@ 'Worth'::text)
+(3 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
+ count
+-------
+ 2
+(1 row)
+
+-- Now check the results from bitmap indexscan
+SET enable_seqscan = OFF;
+SET enable_indexscan = OFF;
+SET enable_bitmapscan = ON;
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
+ QUERY PLAN
+----------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on quad_point_tbl
+ Recheck Cond: (p IS NULL)
+ -> Bitmap Index Scan on sp_quad_ind
+ Index Cond: (p IS NULL)
+(5 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
+ count
+-------
+ 3
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
+ QUERY PLAN
+----------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on quad_point_tbl
+ Recheck Cond: (p IS NOT NULL)
+ -> Bitmap Index Scan on sp_quad_ind
+ Index Cond: (p IS NOT NULL)
+(5 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
+ count
+-------
+ 11000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl;
+ QUERY PLAN
+----------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on quad_point_tbl
+ -> Bitmap Index Scan on sp_quad_ind
+(3 rows)
+
+SELECT count(*) FROM quad_point_tbl;
+ count
+-------
+ 11003
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+ QUERY PLAN
+---------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on quad_point_tbl
+ Recheck Cond: (p <@ '(1000,1000),(200,200)'::box)
+ -> Bitmap Index Scan on sp_quad_ind
+ Index Cond: (p <@ '(1000,1000),(200,200)'::box)
+(5 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+ count
+-------
+ 1057
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+ QUERY PLAN
+---------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on quad_point_tbl
+ Recheck Cond: ('(1000,1000),(200,200)'::box @> p)
+ -> Bitmap Index Scan on sp_quad_ind
+ Index Cond: (p <@ '(1000,1000),(200,200)'::box)
+(5 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+ count
+-------
+ 1057
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on quad_point_tbl
+ Recheck Cond: (p << '(5000,4000)'::point)
+ -> Bitmap Index Scan on sp_quad_ind
+ Index Cond: (p << '(5000,4000)'::point)
+(5 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
+ count
+-------
+ 6000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on quad_point_tbl
+ Recheck Cond: (p >> '(5000,4000)'::point)
+ -> Bitmap Index Scan on sp_quad_ind
+ Index Cond: (p >> '(5000,4000)'::point)
+(5 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
+ count
+-------
+ 4999
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on quad_point_tbl
+ Recheck Cond: (p <^ '(5000,4000)'::point)
+ -> Bitmap Index Scan on sp_quad_ind
+ Index Cond: (p <^ '(5000,4000)'::point)
+(5 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
+ count
+-------
+ 5000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on quad_point_tbl
+ Recheck Cond: (p >^ '(5000,4000)'::point)
+ -> Bitmap Index Scan on sp_quad_ind
+ Index Cond: (p >^ '(5000,4000)'::point)
+(5 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
+ count
+-------
+ 5999
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
+ QUERY PLAN
+------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on quad_point_tbl
+ Recheck Cond: (p ~= '(4585,365)'::point)
+ -> Bitmap Index Scan on sp_quad_ind
+ Index Cond: (p ~= '(4585,365)'::point)
+(5 rows)
+
+SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+ QUERY PLAN
+---------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on kd_point_tbl
+ Recheck Cond: (p <@ '(1000,1000),(200,200)'::box)
+ -> Bitmap Index Scan on sp_kd_ind
+ Index Cond: (p <@ '(1000,1000),(200,200)'::box)
+(5 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+ count
+-------
+ 1057
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+ QUERY PLAN
+---------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on kd_point_tbl
+ Recheck Cond: ('(1000,1000),(200,200)'::box @> p)
+ -> Bitmap Index Scan on sp_kd_ind
+ Index Cond: (p <@ '(1000,1000),(200,200)'::box)
+(5 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+ count
+-------
+ 1057
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on kd_point_tbl
+ Recheck Cond: (p << '(5000,4000)'::point)
+ -> Bitmap Index Scan on sp_kd_ind
+ Index Cond: (p << '(5000,4000)'::point)
+(5 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
+ count
+-------
+ 6000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on kd_point_tbl
+ Recheck Cond: (p >> '(5000,4000)'::point)
+ -> Bitmap Index Scan on sp_kd_ind
+ Index Cond: (p >> '(5000,4000)'::point)
+(5 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
+ count
+-------
+ 4999
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on kd_point_tbl
+ Recheck Cond: (p <^ '(5000,4000)'::point)
+ -> Bitmap Index Scan on sp_kd_ind
+ Index Cond: (p <^ '(5000,4000)'::point)
+(5 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
+ count
+-------
+ 5000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on kd_point_tbl
+ Recheck Cond: (p >^ '(5000,4000)'::point)
+ -> Bitmap Index Scan on sp_kd_ind
+ Index Cond: (p >^ '(5000,4000)'::point)
+(5 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
+ count
+-------
+ 5999
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
+ QUERY PLAN
+------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on kd_point_tbl
+ Recheck Cond: (p ~= '(4585,365)'::point)
+ -> Bitmap Index Scan on sp_kd_ind
+ Index Cond: (p ~= '(4585,365)'::point)
+(5 rows)
+
+SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
+ QUERY PLAN
+-----------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t = 'P0123456789abcdef'::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t = 'P0123456789abcdef'::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
+ count
+-------
+ 1000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
+ QUERY PLAN
+----------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t = 'P0123456789abcde'::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t = 'P0123456789abcde'::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+ QUERY PLAN
+------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t = 'P0123456789abcdefF'::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t = 'P0123456789abcdefF'::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
+ QUERY PLAN
+----------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t < 'Aztec Ct '::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t < 'Aztec Ct '::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
+ count
+-------
+ 272
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
+ QUERY PLAN
+------------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t ~<~ 'Aztec Ct '::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t ~<~ 'Aztec Ct '::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
+ count
+-------
+ 272
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
+ QUERY PLAN
+-----------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t <= 'Aztec Ct '::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t <= 'Aztec Ct '::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
+ count
+-------
+ 273
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
+ QUERY PLAN
+-------------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t ~<=~ 'Aztec Ct '::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t ~<=~ 'Aztec Ct '::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
+ count
+-------
+ 273
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
+ QUERY PLAN
+----------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t = 'Aztec Ct '::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t = 'Aztec Ct '::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
+ QUERY PLAN
+----------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t = 'Worth St '::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t = 'Worth St '::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
+ count
+-------
+ 2
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
+ QUERY PLAN
+-----------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t >= 'Worth St '::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t >= 'Worth St '::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
+ count
+-------
+ 50
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
+ QUERY PLAN
+-------------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t ~>=~ 'Worth St '::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t ~>=~ 'Worth St '::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
+ count
+-------
+ 50
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
+ QUERY PLAN
+----------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t > 'Worth St '::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t > 'Worth St '::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
+ count
+-------
+ 48
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
+ QUERY PLAN
+------------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t ~>~ 'Worth St '::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t ~>~ 'Worth St '::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
+ count
+-------
+ 48
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
+ QUERY PLAN
+------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on radix_text_tbl
+ Recheck Cond: (t ^@ 'Worth'::text)
+ -> Bitmap Index Scan on sp_radix_ind
+ Index Cond: (t ^@ 'Worth'::text)
+(5 rows)
+
+SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
+ count
+-------
+ 2
+(1 row)
+
+RESET enable_seqscan;
+RESET enable_indexscan;
+RESET enable_bitmapscan;
diff --git a/src/test/regress/expected/index_fastpath.out b/src/test/regress/expected/index_fastpath.out
new file mode 100644
index 0000000..accaf3e
--- /dev/null
+++ b/src/test/regress/expected/index_fastpath.out
@@ -0,0 +1,233 @@
+-- test fastpath mechanism for index insertion
+create table fastpath (a int, b text, c numeric);
+create unique index fpindex1 on fastpath(a);
+insert into fastpath values (1, 'b1', 100.00);
+insert into fastpath values (1, 'b1', 100.00); -- unique key check
+ERROR: duplicate key value violates unique constraint "fpindex1"
+DETAIL: Key (a)=(1) already exists.
+truncate fastpath;
+insert into fastpath select generate_series(1,10000), 'b', 100;
+-- vacuum the table so as to improve chances of index-only scans. we can't
+-- guarantee if index-only scans will be picked up in all cases or not, but
+-- that fuzziness actually helps the test.
+vacuum fastpath;
+set enable_seqscan to false;
+set enable_bitmapscan to false;
+select sum(a) from fastpath where a = 6456;
+ sum
+------
+ 6456
+(1 row)
+
+select sum(a) from fastpath where a >= 5000 and a < 5700;
+ sum
+---------
+ 3744650
+(1 row)
+
+-- drop the only index on the table and compute hashes for
+-- a few queries which orders the results in various different ways.
+drop index fpindex1;
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 6167a852b3e0679886b84a5405b5b53d
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ dfcf2bd5e5fea8397d47b2fd14618d31
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+-- now create a multi-column index with both column asc
+create index fpindex2 on fastpath(a, b);
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+-- again, vacuum here either forces index-only scans or creates fuzziness
+vacuum fastpath;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 6167a852b3e0679886b84a5405b5b53d
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ dfcf2bd5e5fea8397d47b2fd14618d31
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+-- same queries with a different kind of index now. the final result must not
+-- change irrespective of what kind of index we have.
+drop index fpindex2;
+create index fpindex3 on fastpath(a desc, b asc);
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+vacuum fastpath;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 6167a852b3e0679886b84a5405b5b53d
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ dfcf2bd5e5fea8397d47b2fd14618d31
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+-- repeat again
+drop index fpindex3;
+create index fpindex4 on fastpath(a asc, b desc);
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+vacuum fastpath;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 6167a852b3e0679886b84a5405b5b53d
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ dfcf2bd5e5fea8397d47b2fd14618d31
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+-- and again, this time indexing by (b, a). Note that column "b" has non-unique
+-- values.
+drop index fpindex4;
+create index fpindex5 on fastpath(b asc, a desc);
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+vacuum fastpath;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 6167a852b3e0679886b84a5405b5b53d
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ dfcf2bd5e5fea8397d47b2fd14618d31
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+-- one last time
+drop index fpindex5;
+create index fpindex6 on fastpath(b desc, a desc);
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+vacuum fastpath;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 6167a852b3e0679886b84a5405b5b53d
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ dfcf2bd5e5fea8397d47b2fd14618d31
+(1 row)
+
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+ md5
+----------------------------------
+ 2ca216010a558a52d7df12f76dfc77ab
+(1 row)
+
+drop table fastpath;
diff --git a/src/test/regress/expected/indexing.out b/src/test/regress/expected/indexing.out
index cfbc06d..e9ac715 100644
--- a/src/test/regress/expected/indexing.out
+++ b/src/test/regress/expected/indexing.out
@@ -1165,239 +1165,6 @@ select tableoid::regclass, * from idxpart order by a;
(8 rows)
drop table idxpart;
--- test fastpath mechanism for index insertion
-create table fastpath (a int, b text, c numeric);
-create unique index fpindex1 on fastpath(a);
-insert into fastpath values (1, 'b1', 100.00);
-insert into fastpath values (1, 'b1', 100.00); -- unique key check
-ERROR: duplicate key value violates unique constraint "fpindex1"
-DETAIL: Key (a)=(1) already exists.
-truncate fastpath;
-insert into fastpath select generate_series(1,10000), 'b', 100;
--- vacuum the table so as to improve chances of index-only scans. we can't
--- guarantee if index-only scans will be picked up in all cases or not, but
--- that fuzziness actually helps the test.
-vacuum fastpath;
-set enable_seqscan to false;
-set enable_bitmapscan to false;
-select sum(a) from fastpath where a = 6456;
- sum
-------
- 6456
-(1 row)
-
-select sum(a) from fastpath where a >= 5000 and a < 5700;
- sum
----------
- 3744650
-(1 row)
-
--- drop the only index on the table and compute hashes for
--- a few queries which orders the results in various different ways.
-drop index fpindex1;
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 6167a852b3e0679886b84a5405b5b53d
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- dfcf2bd5e5fea8397d47b2fd14618d31
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
--- now create a multi-column index with both column asc
-create index fpindex2 on fastpath(a, b);
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
--- again, vacuum here either forces index-only scans or creates fuzziness
-vacuum fastpath;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 6167a852b3e0679886b84a5405b5b53d
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- dfcf2bd5e5fea8397d47b2fd14618d31
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
--- same queries with a different kind of index now. the final result must not
--- change irrespective of what kind of index we have.
-drop index fpindex2;
-create index fpindex3 on fastpath(a desc, b asc);
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
-vacuum fastpath;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 6167a852b3e0679886b84a5405b5b53d
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- dfcf2bd5e5fea8397d47b2fd14618d31
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
--- repeat again
-drop index fpindex3;
-create index fpindex4 on fastpath(a asc, b desc);
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
-vacuum fastpath;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 6167a852b3e0679886b84a5405b5b53d
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- dfcf2bd5e5fea8397d47b2fd14618d31
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
--- and again, this time indexing by (b, a). Note that column "b" has non-unique
--- values.
-drop index fpindex4;
-create index fpindex5 on fastpath(b asc, a desc);
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
-vacuum fastpath;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 6167a852b3e0679886b84a5405b5b53d
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- dfcf2bd5e5fea8397d47b2fd14618d31
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
--- one last time
-drop index fpindex5;
-create index fpindex6 on fastpath(b desc, a desc);
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
-vacuum fastpath;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 6167a852b3e0679886b84a5405b5b53d
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- dfcf2bd5e5fea8397d47b2fd14618d31
-(1 row)
-
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
- md5
-----------------------------------
- 2ca216010a558a52d7df12f76dfc77ab
-(1 row)
-
-drop table fastpath;
-- intentionally leave some objects around
create table idxpart (a int) partition by range (a);
create table idxpart1 partition of idxpart for values from (0) to (100);
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 88fcd52..07e631d 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -6051,883 +6051,3 @@ where exists (select 1 from j3
(13 rows)
drop table j3;
---
--- exercises for the hash join code
---
-begin;
-set local min_parallel_table_scan_size = 0;
-set local parallel_setup_cost = 0;
--- Extract bucket and batch counts from an explain analyze plan. In
--- general we can't make assertions about how many batches (or
--- buckets) will be required because it can vary, but we can in some
--- special cases and we can check for growth.
-create or replace function find_hash(node json)
-returns json language plpgsql
-as
-$$
-declare
- x json;
- child json;
-begin
- if node->>'Node Type' = 'Hash' then
- return node;
- else
- for child in select json_array_elements(node->'Plans')
- loop
- x := find_hash(child);
- if x is not null then
- return x;
- end if;
- end loop;
- return null;
- end if;
-end;
-$$;
-create or replace function hash_join_batches(query text)
-returns table (original int, final int) language plpgsql
-as
-$$
-declare
- whole_plan json;
- hash_node json;
-begin
- for whole_plan in
- execute 'explain (analyze, format ''json'') ' || query
- loop
- hash_node := find_hash(json_extract_path(whole_plan, '0', 'Plan'));
- original := hash_node->>'Original Hash Batches';
- final := hash_node->>'Hash Batches';
- return next;
- end loop;
-end;
-$$;
--- Make a simple relation with well distributed keys and correctly
--- estimated size.
-create table simple as
- select generate_series(1, 20000) AS id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
-alter table simple set (parallel_workers = 2);
-analyze simple;
--- Make a relation whose size we will under-estimate. We want stats
--- to say 1000 rows, but actually there are 20,000 rows.
-create table bigger_than_it_looks as
- select generate_series(1, 20000) as id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
-alter table bigger_than_it_looks set (autovacuum_enabled = 'false');
-alter table bigger_than_it_looks set (parallel_workers = 2);
-analyze bigger_than_it_looks;
-update pg_class set reltuples = 1000 where relname = 'bigger_than_it_looks';
--- Make a relation whose size we underestimate and that also has a
--- kind of skew that breaks our batching scheme. We want stats to say
--- 2 rows, but actually there are 20,000 rows with the same key.
-create table extremely_skewed (id int, t text);
-alter table extremely_skewed set (autovacuum_enabled = 'false');
-alter table extremely_skewed set (parallel_workers = 2);
-analyze extremely_skewed;
-insert into extremely_skewed
- select 42 as id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
- from generate_series(1, 20000);
-update pg_class
- set reltuples = 2, relpages = pg_relation_size('extremely_skewed') / 8192
- where relname = 'extremely_skewed';
--- Make a relation with a couple of enormous tuples.
-create table wide as select generate_series(1, 2) as id, rpad('', 320000, 'x') as t;
-alter table wide set (parallel_workers = 2);
--- The "optimal" case: the hash table fits in memory; we plan for 1
--- batch, we stick to that number, and peak memory usage stays within
--- our work_mem budget
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-set local work_mem = '4MB';
-explain (costs off)
- select count(*) from simple r join simple s using (id);
- QUERY PLAN
-----------------------------------------
- Aggregate
- -> Hash Join
- Hash Cond: (r.id = s.id)
- -> Seq Scan on simple r
- -> Hash
- -> Seq Scan on simple s
-(6 rows)
-
-select count(*) from simple r join simple s using (id);
- count
--------
- 20000
-(1 row)
-
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
- initially_multibatch | increased_batches
-----------------------+-------------------
- f | f
-(1 row)
-
-rollback to settings;
--- parallel with parallel-oblivious hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '4MB';
-set local enable_parallel_hash = off;
-explain (costs off)
- select count(*) from simple r join simple s using (id);
- QUERY PLAN
--------------------------------------------------------
- Finalize Aggregate
- -> Gather
- Workers Planned: 2
- -> Partial Aggregate
- -> Hash Join
- Hash Cond: (r.id = s.id)
- -> Parallel Seq Scan on simple r
- -> Hash
- -> Seq Scan on simple s
-(9 rows)
-
-select count(*) from simple r join simple s using (id);
- count
--------
- 20000
-(1 row)
-
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
- initially_multibatch | increased_batches
-----------------------+-------------------
- f | f
-(1 row)
-
-rollback to settings;
--- parallel with parallel-aware hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '4MB';
-set local enable_parallel_hash = on;
-explain (costs off)
- select count(*) from simple r join simple s using (id);
- QUERY PLAN
--------------------------------------------------------------
- Finalize Aggregate
- -> Gather
- Workers Planned: 2
- -> Partial Aggregate
- -> Parallel Hash Join
- Hash Cond: (r.id = s.id)
- -> Parallel Seq Scan on simple r
- -> Parallel Hash
- -> Parallel Seq Scan on simple s
-(9 rows)
-
-select count(*) from simple r join simple s using (id);
- count
--------
- 20000
-(1 row)
-
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
- initially_multibatch | increased_batches
-----------------------+-------------------
- f | f
-(1 row)
-
-rollback to settings;
--- The "good" case: batches required, but we plan the right number; we
--- plan for some number of batches, and we stick to that number, and
--- peak memory usage says within our work_mem budget
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-set local work_mem = '128kB';
-explain (costs off)
- select count(*) from simple r join simple s using (id);
- QUERY PLAN
-----------------------------------------
- Aggregate
- -> Hash Join
- Hash Cond: (r.id = s.id)
- -> Seq Scan on simple r
- -> Hash
- -> Seq Scan on simple s
-(6 rows)
-
-select count(*) from simple r join simple s using (id);
- count
--------
- 20000
-(1 row)
-
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
- initially_multibatch | increased_batches
-----------------------+-------------------
- t | f
-(1 row)
-
-rollback to settings;
--- parallel with parallel-oblivious hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '128kB';
-set local enable_parallel_hash = off;
-explain (costs off)
- select count(*) from simple r join simple s using (id);
- QUERY PLAN
--------------------------------------------------------
- Finalize Aggregate
- -> Gather
- Workers Planned: 2
- -> Partial Aggregate
- -> Hash Join
- Hash Cond: (r.id = s.id)
- -> Parallel Seq Scan on simple r
- -> Hash
- -> Seq Scan on simple s
-(9 rows)
-
-select count(*) from simple r join simple s using (id);
- count
--------
- 20000
-(1 row)
-
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
- initially_multibatch | increased_batches
-----------------------+-------------------
- t | f
-(1 row)
-
-rollback to settings;
--- parallel with parallel-aware hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '192kB';
-set local enable_parallel_hash = on;
-explain (costs off)
- select count(*) from simple r join simple s using (id);
- QUERY PLAN
--------------------------------------------------------------
- Finalize Aggregate
- -> Gather
- Workers Planned: 2
- -> Partial Aggregate
- -> Parallel Hash Join
- Hash Cond: (r.id = s.id)
- -> Parallel Seq Scan on simple r
- -> Parallel Hash
- -> Parallel Seq Scan on simple s
-(9 rows)
-
-select count(*) from simple r join simple s using (id);
- count
--------
- 20000
-(1 row)
-
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
- initially_multibatch | increased_batches
-----------------------+-------------------
- t | f
-(1 row)
-
-rollback to settings;
--- The "bad" case: during execution we need to increase number of
--- batches; in this case we plan for 1 batch, and increase at least a
--- couple of times, and peak memory usage stays within our work_mem
--- budget
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-set local work_mem = '128kB';
-explain (costs off)
- select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
- QUERY PLAN
-------------------------------------------------------
- Aggregate
- -> Hash Join
- Hash Cond: (r.id = s.id)
- -> Seq Scan on simple r
- -> Hash
- -> Seq Scan on bigger_than_it_looks s
-(6 rows)
-
-select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
- count
--------
- 20000
-(1 row)
-
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
-$$);
- initially_multibatch | increased_batches
-----------------------+-------------------
- f | t
-(1 row)
-
-rollback to settings;
--- parallel with parallel-oblivious hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '128kB';
-set local enable_parallel_hash = off;
-explain (costs off)
- select count(*) from simple r join bigger_than_it_looks s using (id);
- QUERY PLAN
-------------------------------------------------------------------
- Finalize Aggregate
- -> Gather
- Workers Planned: 2
- -> Partial Aggregate
- -> Hash Join
- Hash Cond: (r.id = s.id)
- -> Parallel Seq Scan on simple r
- -> Hash
- -> Seq Scan on bigger_than_it_looks s
-(9 rows)
-
-select count(*) from simple r join bigger_than_it_looks s using (id);
- count
--------
- 20000
-(1 row)
-
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join bigger_than_it_looks s using (id);
-$$);
- initially_multibatch | increased_batches
-----------------------+-------------------
- f | t
-(1 row)
-
-rollback to settings;
--- parallel with parallel-aware hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 1;
-set local work_mem = '192kB';
-set local enable_parallel_hash = on;
-explain (costs off)
- select count(*) from simple r join bigger_than_it_looks s using (id);
- QUERY PLAN
----------------------------------------------------------------------------
- Finalize Aggregate
- -> Gather
- Workers Planned: 1
- -> Partial Aggregate
- -> Parallel Hash Join
- Hash Cond: (r.id = s.id)
- -> Parallel Seq Scan on simple r
- -> Parallel Hash
- -> Parallel Seq Scan on bigger_than_it_looks s
-(9 rows)
-
-select count(*) from simple r join bigger_than_it_looks s using (id);
- count
--------
- 20000
-(1 row)
-
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join bigger_than_it_looks s using (id);
-$$);
- initially_multibatch | increased_batches
-----------------------+-------------------
- f | t
-(1 row)
-
-rollback to settings;
--- The "ugly" case: increasing the number of batches during execution
--- doesn't help, so stop trying to fit in work_mem and hope for the
--- best; in this case we plan for 1 batch, increases just once and
--- then stop increasing because that didn't help at all, so we blow
--- right through the work_mem budget and hope for the best...
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-set local work_mem = '128kB';
-explain (costs off)
- select count(*) from simple r join extremely_skewed s using (id);
- QUERY PLAN
---------------------------------------------------
- Aggregate
- -> Hash Join
- Hash Cond: (r.id = s.id)
- -> Seq Scan on simple r
- -> Hash
- -> Seq Scan on extremely_skewed s
-(6 rows)
-
-select count(*) from simple r join extremely_skewed s using (id);
- count
--------
- 20000
-(1 row)
-
-select * from hash_join_batches(
-$$
- select count(*) from simple r join extremely_skewed s using (id);
-$$);
- original | final
-----------+-------
- 1 | 2
-(1 row)
-
-rollback to settings;
--- parallel with parallel-oblivious hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '128kB';
-set local enable_parallel_hash = off;
-explain (costs off)
- select count(*) from simple r join extremely_skewed s using (id);
- QUERY PLAN
---------------------------------------------------------
- Aggregate
- -> Gather
- Workers Planned: 2
- -> Hash Join
- Hash Cond: (r.id = s.id)
- -> Parallel Seq Scan on simple r
- -> Hash
- -> Seq Scan on extremely_skewed s
-(8 rows)
-
-select count(*) from simple r join extremely_skewed s using (id);
- count
--------
- 20000
-(1 row)
-
-select * from hash_join_batches(
-$$
- select count(*) from simple r join extremely_skewed s using (id);
-$$);
- original | final
-----------+-------
- 1 | 2
-(1 row)
-
-rollback to settings;
--- parallel with parallel-aware hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 1;
-set local work_mem = '128kB';
-set local enable_parallel_hash = on;
-explain (costs off)
- select count(*) from simple r join extremely_skewed s using (id);
- QUERY PLAN
------------------------------------------------------------------------
- Finalize Aggregate
- -> Gather
- Workers Planned: 1
- -> Partial Aggregate
- -> Parallel Hash Join
- Hash Cond: (r.id = s.id)
- -> Parallel Seq Scan on simple r
- -> Parallel Hash
- -> Parallel Seq Scan on extremely_skewed s
-(9 rows)
-
-select count(*) from simple r join extremely_skewed s using (id);
- count
--------
- 20000
-(1 row)
-
-select * from hash_join_batches(
-$$
- select count(*) from simple r join extremely_skewed s using (id);
-$$);
- original | final
-----------+-------
- 1 | 4
-(1 row)
-
-rollback to settings;
--- A couple of other hash join tests unrelated to work_mem management.
--- Check that EXPLAIN ANALYZE has data even if the leader doesn't participate
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '4MB';
-set local parallel_leader_participation = off;
-select * from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
- original | final
-----------+-------
- 1 | 1
-(1 row)
-
-rollback to settings;
--- Exercise rescans. We'll turn off parallel_leader_participation so
--- that we can check that instrumentation comes back correctly.
-create table join_foo as select generate_series(1, 3) as id, 'xxxxx'::text as t;
-alter table join_foo set (parallel_workers = 0);
-create table join_bar as select generate_series(1, 10000) as id, 'xxxxx'::text as t;
-alter table join_bar set (parallel_workers = 2);
--- multi-batch with rescan, parallel-oblivious
-savepoint settings;
-set enable_parallel_hash = off;
-set parallel_leader_participation = off;
-set min_parallel_table_scan_size = 0;
-set parallel_setup_cost = 0;
-set parallel_tuple_cost = 0;
-set max_parallel_workers_per_gather = 2;
-set enable_material = off;
-set enable_mergejoin = off;
-set work_mem = '64kB';
-explain (costs off)
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
- QUERY PLAN
-------------------------------------------------------------------------------------
- Aggregate
- -> Nested Loop Left Join
- Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1)))
- -> Seq Scan on join_foo
- -> Gather
- Workers Planned: 2
- -> Hash Join
- Hash Cond: (b1.id = b2.id)
- -> Parallel Seq Scan on join_bar b1
- -> Hash
- -> Seq Scan on join_bar b2
-(11 rows)
-
-select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
- count
--------
- 3
-(1 row)
-
-select final > 1 as multibatch
- from hash_join_batches(
-$$
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-$$);
- multibatch
-------------
- t
-(1 row)
-
-rollback to settings;
--- single-batch with rescan, parallel-oblivious
-savepoint settings;
-set enable_parallel_hash = off;
-set parallel_leader_participation = off;
-set min_parallel_table_scan_size = 0;
-set parallel_setup_cost = 0;
-set parallel_tuple_cost = 0;
-set max_parallel_workers_per_gather = 2;
-set enable_material = off;
-set enable_mergejoin = off;
-set work_mem = '4MB';
-explain (costs off)
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
- QUERY PLAN
-------------------------------------------------------------------------------------
- Aggregate
- -> Nested Loop Left Join
- Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1)))
- -> Seq Scan on join_foo
- -> Gather
- Workers Planned: 2
- -> Hash Join
- Hash Cond: (b1.id = b2.id)
- -> Parallel Seq Scan on join_bar b1
- -> Hash
- -> Seq Scan on join_bar b2
-(11 rows)
-
-select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
- count
--------
- 3
-(1 row)
-
-select final > 1 as multibatch
- from hash_join_batches(
-$$
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-$$);
- multibatch
-------------
- f
-(1 row)
-
-rollback to settings;
--- multi-batch with rescan, parallel-aware
-savepoint settings;
-set enable_parallel_hash = on;
-set parallel_leader_participation = off;
-set min_parallel_table_scan_size = 0;
-set parallel_setup_cost = 0;
-set parallel_tuple_cost = 0;
-set max_parallel_workers_per_gather = 2;
-set enable_material = off;
-set enable_mergejoin = off;
-set work_mem = '64kB';
-explain (costs off)
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
- QUERY PLAN
-------------------------------------------------------------------------------------
- Aggregate
- -> Nested Loop Left Join
- Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1)))
- -> Seq Scan on join_foo
- -> Gather
- Workers Planned: 2
- -> Parallel Hash Join
- Hash Cond: (b1.id = b2.id)
- -> Parallel Seq Scan on join_bar b1
- -> Parallel Hash
- -> Parallel Seq Scan on join_bar b2
-(11 rows)
-
-select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
- count
--------
- 3
-(1 row)
-
-select final > 1 as multibatch
- from hash_join_batches(
-$$
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-$$);
- multibatch
-------------
- t
-(1 row)
-
-rollback to settings;
--- single-batch with rescan, parallel-aware
-savepoint settings;
-set enable_parallel_hash = on;
-set parallel_leader_participation = off;
-set min_parallel_table_scan_size = 0;
-set parallel_setup_cost = 0;
-set parallel_tuple_cost = 0;
-set max_parallel_workers_per_gather = 2;
-set enable_material = off;
-set enable_mergejoin = off;
-set work_mem = '4MB';
-explain (costs off)
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
- QUERY PLAN
-------------------------------------------------------------------------------------
- Aggregate
- -> Nested Loop Left Join
- Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1)))
- -> Seq Scan on join_foo
- -> Gather
- Workers Planned: 2
- -> Parallel Hash Join
- Hash Cond: (b1.id = b2.id)
- -> Parallel Seq Scan on join_bar b1
- -> Parallel Hash
- -> Parallel Seq Scan on join_bar b2
-(11 rows)
-
-select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
- count
--------
- 3
-(1 row)
-
-select final > 1 as multibatch
- from hash_join_batches(
-$$
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-$$);
- multibatch
-------------
- f
-(1 row)
-
-rollback to settings;
--- A full outer join where every record is matched.
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-explain (costs off)
- select count(*) from simple r full outer join simple s using (id);
- QUERY PLAN
-----------------------------------------
- Aggregate
- -> Hash Full Join
- Hash Cond: (r.id = s.id)
- -> Seq Scan on simple r
- -> Hash
- -> Seq Scan on simple s
-(6 rows)
-
-select count(*) from simple r full outer join simple s using (id);
- count
--------
- 20000
-(1 row)
-
-rollback to settings;
--- parallelism not possible with parallel-oblivious outer hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-explain (costs off)
- select count(*) from simple r full outer join simple s using (id);
- QUERY PLAN
-----------------------------------------
- Aggregate
- -> Hash Full Join
- Hash Cond: (r.id = s.id)
- -> Seq Scan on simple r
- -> Hash
- -> Seq Scan on simple s
-(6 rows)
-
-select count(*) from simple r full outer join simple s using (id);
- count
--------
- 20000
-(1 row)
-
-rollback to settings;
--- An full outer join where every record is not matched.
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-explain (costs off)
- select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
- QUERY PLAN
-----------------------------------------
- Aggregate
- -> Hash Full Join
- Hash Cond: ((0 - s.id) = r.id)
- -> Seq Scan on simple s
- -> Hash
- -> Seq Scan on simple r
-(6 rows)
-
-select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
- count
--------
- 40000
-(1 row)
-
-rollback to settings;
--- parallelism not possible with parallel-oblivious outer hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-explain (costs off)
- select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
- QUERY PLAN
-----------------------------------------
- Aggregate
- -> Hash Full Join
- Hash Cond: ((0 - s.id) = r.id)
- -> Seq Scan on simple s
- -> Hash
- -> Seq Scan on simple r
-(6 rows)
-
-select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
- count
--------
- 40000
-(1 row)
-
-rollback to settings;
--- exercise special code paths for huge tuples (note use of non-strict
--- expression and left join required to get the detoasted tuple into
--- the hash table)
--- parallel with parallel-aware hash join (hits ExecParallelHashLoadTuple and
--- sts_puttuple oversized tuple cases because it's multi-batch)
-savepoint settings;
-set max_parallel_workers_per_gather = 2;
-set enable_parallel_hash = on;
-set work_mem = '128kB';
-explain (costs off)
- select length(max(s.t))
- from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
- QUERY PLAN
-----------------------------------------------------------------
- Finalize Aggregate
- -> Gather
- Workers Planned: 2
- -> Partial Aggregate
- -> Parallel Hash Left Join
- Hash Cond: (wide.id = wide_1.id)
- -> Parallel Seq Scan on wide
- -> Parallel Hash
- -> Parallel Seq Scan on wide wide_1
-(9 rows)
-
-select length(max(s.t))
-from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
- length
---------
- 320000
-(1 row)
-
-select final > 1 as multibatch
- from hash_join_batches(
-$$
- select length(max(s.t))
- from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
-$$);
- multibatch
-------------
- t
-(1 row)
-
-rollback to settings;
-rollback;
diff --git a/src/test/regress/expected/join_hash.out b/src/test/regress/expected/join_hash.out
new file mode 100644
index 0000000..9eee39b
--- /dev/null
+++ b/src/test/regress/expected/join_hash.out
@@ -0,0 +1,880 @@
+--
+-- exercises for the hash join code
+--
+begin;
+set local min_parallel_table_scan_size = 0;
+set local parallel_setup_cost = 0;
+-- Extract bucket and batch counts from an explain analyze plan. In
+-- general we can't make assertions about how many batches (or
+-- buckets) will be required because it can vary, but we can in some
+-- special cases and we can check for growth.
+create or replace function find_hash(node json)
+returns json language plpgsql
+as
+$$
+declare
+ x json;
+ child json;
+begin
+ if node->>'Node Type' = 'Hash' then
+ return node;
+ else
+ for child in select json_array_elements(node->'Plans')
+ loop
+ x := find_hash(child);
+ if x is not null then
+ return x;
+ end if;
+ end loop;
+ return null;
+ end if;
+end;
+$$;
+create or replace function hash_join_batches(query text)
+returns table (original int, final int) language plpgsql
+as
+$$
+declare
+ whole_plan json;
+ hash_node json;
+begin
+ for whole_plan in
+ execute 'explain (analyze, format ''json'') ' || query
+ loop
+ hash_node := find_hash(json_extract_path(whole_plan, '0', 'Plan'));
+ original := hash_node->>'Original Hash Batches';
+ final := hash_node->>'Hash Batches';
+ return next;
+ end loop;
+end;
+$$;
+-- Make a simple relation with well distributed keys and correctly
+-- estimated size.
+create table simple as
+ select generate_series(1, 20000) AS id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
+alter table simple set (parallel_workers = 2);
+analyze simple;
+-- Make a relation whose size we will under-estimate. We want stats
+-- to say 1000 rows, but actually there are 20,000 rows.
+create table bigger_than_it_looks as
+ select generate_series(1, 20000) as id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
+alter table bigger_than_it_looks set (autovacuum_enabled = 'false');
+alter table bigger_than_it_looks set (parallel_workers = 2);
+analyze bigger_than_it_looks;
+update pg_class set reltuples = 1000 where relname = 'bigger_than_it_looks';
+-- Make a relation whose size we underestimate and that also has a
+-- kind of skew that breaks our batching scheme. We want stats to say
+-- 2 rows, but actually there are 20,000 rows with the same key.
+create table extremely_skewed (id int, t text);
+alter table extremely_skewed set (autovacuum_enabled = 'false');
+alter table extremely_skewed set (parallel_workers = 2);
+analyze extremely_skewed;
+insert into extremely_skewed
+ select 42 as id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+ from generate_series(1, 20000);
+update pg_class
+ set reltuples = 2, relpages = pg_relation_size('extremely_skewed') / 8192
+ where relname = 'extremely_skewed';
+-- Make a relation with a couple of enormous tuples.
+create table wide as select generate_series(1, 2) as id, rpad('', 320000, 'x') as t;
+alter table wide set (parallel_workers = 2);
+-- The "optimal" case: the hash table fits in memory; we plan for 1
+-- batch, we stick to that number, and peak memory usage stays within
+-- our work_mem budget
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+set local work_mem = '4MB';
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+ QUERY PLAN
+----------------------------------------
+ Aggregate
+ -> Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Seq Scan on simple r
+ -> Hash
+ -> Seq Scan on simple s
+(6 rows)
+
+select count(*) from simple r join simple s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+ initially_multibatch | increased_batches
+----------------------+-------------------
+ f | f
+(1 row)
+
+rollback to settings;
+-- parallel with parallel-oblivious hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '4MB';
+set local enable_parallel_hash = off;
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+ QUERY PLAN
+-------------------------------------------------------
+ Finalize Aggregate
+ -> Gather
+ Workers Planned: 2
+ -> Partial Aggregate
+ -> Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Parallel Seq Scan on simple r
+ -> Hash
+ -> Seq Scan on simple s
+(9 rows)
+
+select count(*) from simple r join simple s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+ initially_multibatch | increased_batches
+----------------------+-------------------
+ f | f
+(1 row)
+
+rollback to settings;
+-- parallel with parallel-aware hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '4MB';
+set local enable_parallel_hash = on;
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+ QUERY PLAN
+-------------------------------------------------------------
+ Finalize Aggregate
+ -> Gather
+ Workers Planned: 2
+ -> Partial Aggregate
+ -> Parallel Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Parallel Seq Scan on simple r
+ -> Parallel Hash
+ -> Parallel Seq Scan on simple s
+(9 rows)
+
+select count(*) from simple r join simple s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+ initially_multibatch | increased_batches
+----------------------+-------------------
+ f | f
+(1 row)
+
+rollback to settings;
+-- The "good" case: batches required, but we plan the right number; we
+-- plan for some number of batches, and we stick to that number, and
+-- peak memory usage says within our work_mem budget
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+set local work_mem = '128kB';
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+ QUERY PLAN
+----------------------------------------
+ Aggregate
+ -> Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Seq Scan on simple r
+ -> Hash
+ -> Seq Scan on simple s
+(6 rows)
+
+select count(*) from simple r join simple s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+ initially_multibatch | increased_batches
+----------------------+-------------------
+ t | f
+(1 row)
+
+rollback to settings;
+-- parallel with parallel-oblivious hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '128kB';
+set local enable_parallel_hash = off;
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+ QUERY PLAN
+-------------------------------------------------------
+ Finalize Aggregate
+ -> Gather
+ Workers Planned: 2
+ -> Partial Aggregate
+ -> Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Parallel Seq Scan on simple r
+ -> Hash
+ -> Seq Scan on simple s
+(9 rows)
+
+select count(*) from simple r join simple s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+ initially_multibatch | increased_batches
+----------------------+-------------------
+ t | f
+(1 row)
+
+rollback to settings;
+-- parallel with parallel-aware hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '192kB';
+set local enable_parallel_hash = on;
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+ QUERY PLAN
+-------------------------------------------------------------
+ Finalize Aggregate
+ -> Gather
+ Workers Planned: 2
+ -> Partial Aggregate
+ -> Parallel Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Parallel Seq Scan on simple r
+ -> Parallel Hash
+ -> Parallel Seq Scan on simple s
+(9 rows)
+
+select count(*) from simple r join simple s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+ initially_multibatch | increased_batches
+----------------------+-------------------
+ t | f
+(1 row)
+
+rollback to settings;
+-- The "bad" case: during execution we need to increase number of
+-- batches; in this case we plan for 1 batch, and increase at least a
+-- couple of times, and peak memory usage stays within our work_mem
+-- budget
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+set local work_mem = '128kB';
+explain (costs off)
+ select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
+ QUERY PLAN
+------------------------------------------------------
+ Aggregate
+ -> Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Seq Scan on simple r
+ -> Hash
+ -> Seq Scan on bigger_than_it_looks s
+(6 rows)
+
+select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
+ count
+-------
+ 20000
+(1 row)
+
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
+$$);
+ initially_multibatch | increased_batches
+----------------------+-------------------
+ f | t
+(1 row)
+
+rollback to settings;
+-- parallel with parallel-oblivious hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '128kB';
+set local enable_parallel_hash = off;
+explain (costs off)
+ select count(*) from simple r join bigger_than_it_looks s using (id);
+ QUERY PLAN
+------------------------------------------------------------------
+ Finalize Aggregate
+ -> Gather
+ Workers Planned: 2
+ -> Partial Aggregate
+ -> Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Parallel Seq Scan on simple r
+ -> Hash
+ -> Seq Scan on bigger_than_it_looks s
+(9 rows)
+
+select count(*) from simple r join bigger_than_it_looks s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join bigger_than_it_looks s using (id);
+$$);
+ initially_multibatch | increased_batches
+----------------------+-------------------
+ f | t
+(1 row)
+
+rollback to settings;
+-- parallel with parallel-aware hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 1;
+set local work_mem = '192kB';
+set local enable_parallel_hash = on;
+explain (costs off)
+ select count(*) from simple r join bigger_than_it_looks s using (id);
+ QUERY PLAN
+---------------------------------------------------------------------------
+ Finalize Aggregate
+ -> Gather
+ Workers Planned: 1
+ -> Partial Aggregate
+ -> Parallel Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Parallel Seq Scan on simple r
+ -> Parallel Hash
+ -> Parallel Seq Scan on bigger_than_it_looks s
+(9 rows)
+
+select count(*) from simple r join bigger_than_it_looks s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join bigger_than_it_looks s using (id);
+$$);
+ initially_multibatch | increased_batches
+----------------------+-------------------
+ f | t
+(1 row)
+
+rollback to settings;
+-- The "ugly" case: increasing the number of batches during execution
+-- doesn't help, so stop trying to fit in work_mem and hope for the
+-- best; in this case we plan for 1 batch, increases just once and
+-- then stop increasing because that didn't help at all, so we blow
+-- right through the work_mem budget and hope for the best...
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+set local work_mem = '128kB';
+explain (costs off)
+ select count(*) from simple r join extremely_skewed s using (id);
+ QUERY PLAN
+--------------------------------------------------
+ Aggregate
+ -> Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Seq Scan on simple r
+ -> Hash
+ -> Seq Scan on extremely_skewed s
+(6 rows)
+
+select count(*) from simple r join extremely_skewed s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+select * from hash_join_batches(
+$$
+ select count(*) from simple r join extremely_skewed s using (id);
+$$);
+ original | final
+----------+-------
+ 1 | 2
+(1 row)
+
+rollback to settings;
+-- parallel with parallel-oblivious hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '128kB';
+set local enable_parallel_hash = off;
+explain (costs off)
+ select count(*) from simple r join extremely_skewed s using (id);
+ QUERY PLAN
+--------------------------------------------------------
+ Aggregate
+ -> Gather
+ Workers Planned: 2
+ -> Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Parallel Seq Scan on simple r
+ -> Hash
+ -> Seq Scan on extremely_skewed s
+(8 rows)
+
+select count(*) from simple r join extremely_skewed s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+select * from hash_join_batches(
+$$
+ select count(*) from simple r join extremely_skewed s using (id);
+$$);
+ original | final
+----------+-------
+ 1 | 2
+(1 row)
+
+rollback to settings;
+-- parallel with parallel-aware hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 1;
+set local work_mem = '128kB';
+set local enable_parallel_hash = on;
+explain (costs off)
+ select count(*) from simple r join extremely_skewed s using (id);
+ QUERY PLAN
+-----------------------------------------------------------------------
+ Finalize Aggregate
+ -> Gather
+ Workers Planned: 1
+ -> Partial Aggregate
+ -> Parallel Hash Join
+ Hash Cond: (r.id = s.id)
+ -> Parallel Seq Scan on simple r
+ -> Parallel Hash
+ -> Parallel Seq Scan on extremely_skewed s
+(9 rows)
+
+select count(*) from simple r join extremely_skewed s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+select * from hash_join_batches(
+$$
+ select count(*) from simple r join extremely_skewed s using (id);
+$$);
+ original | final
+----------+-------
+ 1 | 4
+(1 row)
+
+rollback to settings;
+-- A couple of other hash join tests unrelated to work_mem management.
+-- Check that EXPLAIN ANALYZE has data even if the leader doesn't participate
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '4MB';
+set local parallel_leader_participation = off;
+select * from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+ original | final
+----------+-------
+ 1 | 1
+(1 row)
+
+rollback to settings;
+-- Exercise rescans. We'll turn off parallel_leader_participation so
+-- that we can check that instrumentation comes back correctly.
+create table join_foo as select generate_series(1, 3) as id, 'xxxxx'::text as t;
+alter table join_foo set (parallel_workers = 0);
+create table join_bar as select generate_series(1, 10000) as id, 'xxxxx'::text as t;
+alter table join_bar set (parallel_workers = 2);
+-- multi-batch with rescan, parallel-oblivious
+savepoint settings;
+set enable_parallel_hash = off;
+set parallel_leader_participation = off;
+set min_parallel_table_scan_size = 0;
+set parallel_setup_cost = 0;
+set parallel_tuple_cost = 0;
+set max_parallel_workers_per_gather = 2;
+set enable_material = off;
+set enable_mergejoin = off;
+set work_mem = '64kB';
+explain (costs off)
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+ QUERY PLAN
+------------------------------------------------------------------------------------
+ Aggregate
+ -> Nested Loop Left Join
+ Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1)))
+ -> Seq Scan on join_foo
+ -> Gather
+ Workers Planned: 2
+ -> Hash Join
+ Hash Cond: (b1.id = b2.id)
+ -> Parallel Seq Scan on join_bar b1
+ -> Hash
+ -> Seq Scan on join_bar b2
+(11 rows)
+
+select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+ count
+-------
+ 3
+(1 row)
+
+select final > 1 as multibatch
+ from hash_join_batches(
+$$
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+$$);
+ multibatch
+------------
+ t
+(1 row)
+
+rollback to settings;
+-- single-batch with rescan, parallel-oblivious
+savepoint settings;
+set enable_parallel_hash = off;
+set parallel_leader_participation = off;
+set min_parallel_table_scan_size = 0;
+set parallel_setup_cost = 0;
+set parallel_tuple_cost = 0;
+set max_parallel_workers_per_gather = 2;
+set enable_material = off;
+set enable_mergejoin = off;
+set work_mem = '4MB';
+explain (costs off)
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+ QUERY PLAN
+------------------------------------------------------------------------------------
+ Aggregate
+ -> Nested Loop Left Join
+ Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1)))
+ -> Seq Scan on join_foo
+ -> Gather
+ Workers Planned: 2
+ -> Hash Join
+ Hash Cond: (b1.id = b2.id)
+ -> Parallel Seq Scan on join_bar b1
+ -> Hash
+ -> Seq Scan on join_bar b2
+(11 rows)
+
+select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+ count
+-------
+ 3
+(1 row)
+
+select final > 1 as multibatch
+ from hash_join_batches(
+$$
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+$$);
+ multibatch
+------------
+ f
+(1 row)
+
+rollback to settings;
+-- multi-batch with rescan, parallel-aware
+savepoint settings;
+set enable_parallel_hash = on;
+set parallel_leader_participation = off;
+set min_parallel_table_scan_size = 0;
+set parallel_setup_cost = 0;
+set parallel_tuple_cost = 0;
+set max_parallel_workers_per_gather = 2;
+set enable_material = off;
+set enable_mergejoin = off;
+set work_mem = '64kB';
+explain (costs off)
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+ QUERY PLAN
+------------------------------------------------------------------------------------
+ Aggregate
+ -> Nested Loop Left Join
+ Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1)))
+ -> Seq Scan on join_foo
+ -> Gather
+ Workers Planned: 2
+ -> Parallel Hash Join
+ Hash Cond: (b1.id = b2.id)
+ -> Parallel Seq Scan on join_bar b1
+ -> Parallel Hash
+ -> Parallel Seq Scan on join_bar b2
+(11 rows)
+
+select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+ count
+-------
+ 3
+(1 row)
+
+select final > 1 as multibatch
+ from hash_join_batches(
+$$
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+$$);
+ multibatch
+------------
+ t
+(1 row)
+
+rollback to settings;
+-- single-batch with rescan, parallel-aware
+savepoint settings;
+set enable_parallel_hash = on;
+set parallel_leader_participation = off;
+set min_parallel_table_scan_size = 0;
+set parallel_setup_cost = 0;
+set parallel_tuple_cost = 0;
+set max_parallel_workers_per_gather = 2;
+set enable_material = off;
+set enable_mergejoin = off;
+set work_mem = '4MB';
+explain (costs off)
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+ QUERY PLAN
+------------------------------------------------------------------------------------
+ Aggregate
+ -> Nested Loop Left Join
+ Join Filter: ((join_foo.id < (b1.id + 1)) AND (join_foo.id > (b1.id - 1)))
+ -> Seq Scan on join_foo
+ -> Gather
+ Workers Planned: 2
+ -> Parallel Hash Join
+ Hash Cond: (b1.id = b2.id)
+ -> Parallel Seq Scan on join_bar b1
+ -> Parallel Hash
+ -> Parallel Seq Scan on join_bar b2
+(11 rows)
+
+select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+ count
+-------
+ 3
+(1 row)
+
+select final > 1 as multibatch
+ from hash_join_batches(
+$$
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+$$);
+ multibatch
+------------
+ f
+(1 row)
+
+rollback to settings;
+-- A full outer join where every record is matched.
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+explain (costs off)
+ select count(*) from simple r full outer join simple s using (id);
+ QUERY PLAN
+----------------------------------------
+ Aggregate
+ -> Hash Full Join
+ Hash Cond: (r.id = s.id)
+ -> Seq Scan on simple r
+ -> Hash
+ -> Seq Scan on simple s
+(6 rows)
+
+select count(*) from simple r full outer join simple s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+rollback to settings;
+-- parallelism not possible with parallel-oblivious outer hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+explain (costs off)
+ select count(*) from simple r full outer join simple s using (id);
+ QUERY PLAN
+----------------------------------------
+ Aggregate
+ -> Hash Full Join
+ Hash Cond: (r.id = s.id)
+ -> Seq Scan on simple r
+ -> Hash
+ -> Seq Scan on simple s
+(6 rows)
+
+select count(*) from simple r full outer join simple s using (id);
+ count
+-------
+ 20000
+(1 row)
+
+rollback to settings;
+-- An full outer join where every record is not matched.
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+explain (costs off)
+ select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
+ QUERY PLAN
+----------------------------------------
+ Aggregate
+ -> Hash Full Join
+ Hash Cond: ((0 - s.id) = r.id)
+ -> Seq Scan on simple s
+ -> Hash
+ -> Seq Scan on simple r
+(6 rows)
+
+select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
+ count
+-------
+ 40000
+(1 row)
+
+rollback to settings;
+-- parallelism not possible with parallel-oblivious outer hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+explain (costs off)
+ select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
+ QUERY PLAN
+----------------------------------------
+ Aggregate
+ -> Hash Full Join
+ Hash Cond: ((0 - s.id) = r.id)
+ -> Seq Scan on simple s
+ -> Hash
+ -> Seq Scan on simple r
+(6 rows)
+
+select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
+ count
+-------
+ 40000
+(1 row)
+
+rollback to settings;
+-- exercise special code paths for huge tuples (note use of non-strict
+-- expression and left join required to get the detoasted tuple into
+-- the hash table)
+-- parallel with parallel-aware hash join (hits ExecParallelHashLoadTuple and
+-- sts_puttuple oversized tuple cases because it's multi-batch)
+savepoint settings;
+set max_parallel_workers_per_gather = 2;
+set enable_parallel_hash = on;
+set work_mem = '128kB';
+explain (costs off)
+ select length(max(s.t))
+ from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
+ QUERY PLAN
+----------------------------------------------------------------
+ Finalize Aggregate
+ -> Gather
+ Workers Planned: 2
+ -> Partial Aggregate
+ -> Parallel Hash Left Join
+ Hash Cond: (wide.id = wide_1.id)
+ -> Parallel Seq Scan on wide
+ -> Parallel Hash
+ -> Parallel Seq Scan on wide wide_1
+(9 rows)
+
+select length(max(s.t))
+from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
+ length
+--------
+ 320000
+(1 row)
+
+select final > 1 as multibatch
+ from hash_join_batches(
+$$
+ select length(max(s.t))
+ from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
+$$);
+ multibatch
+------------
+ t
+(1 row)
+
+rollback to settings;
+rollback;
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index d2f68e1..5613a46 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -1915,259 +1915,6 @@ SELECT * FROM perform_test;
drop table perform_test;
--
--- Test error trapping
---
-create function trap_zero_divide(int) returns int as $$
-declare x int;
- sx smallint;
-begin
- begin -- start a subtransaction
- raise notice 'should see this';
- x := 100 / $1;
- raise notice 'should see this only if % <> 0', $1;
- sx := $1;
- raise notice 'should see this only if % fits in smallint', $1;
- if $1 < 0 then
- raise exception '% is less than zero', $1;
- end if;
- exception
- when division_by_zero then
- raise notice 'caught division_by_zero';
- x := -1;
- when NUMERIC_VALUE_OUT_OF_RANGE then
- raise notice 'caught numeric_value_out_of_range';
- x := -2;
- end;
- return x;
-end$$ language plpgsql;
-select trap_zero_divide(50);
-NOTICE: should see this
-NOTICE: should see this only if 50 <> 0
-NOTICE: should see this only if 50 fits in smallint
- trap_zero_divide
-------------------
- 2
-(1 row)
-
-select trap_zero_divide(0);
-NOTICE: should see this
-NOTICE: caught division_by_zero
- trap_zero_divide
-------------------
- -1
-(1 row)
-
-select trap_zero_divide(100000);
-NOTICE: should see this
-NOTICE: should see this only if 100000 <> 0
-NOTICE: caught numeric_value_out_of_range
- trap_zero_divide
-------------------
- -2
-(1 row)
-
-select trap_zero_divide(-100);
-NOTICE: should see this
-NOTICE: should see this only if -100 <> 0
-NOTICE: should see this only if -100 fits in smallint
-ERROR: -100 is less than zero
-CONTEXT: PL/pgSQL function trap_zero_divide(integer) line 12 at RAISE
-create function trap_matching_test(int) returns int as $$
-declare x int;
- sx smallint;
- y int;
-begin
- begin -- start a subtransaction
- x := 100 / $1;
- sx := $1;
- select into y unique1 from tenk1 where unique2 =
- (select unique2 from tenk1 b where ten = $1);
- exception
- when data_exception then -- category match
- raise notice 'caught data_exception';
- x := -1;
- when NUMERIC_VALUE_OUT_OF_RANGE OR CARDINALITY_VIOLATION then
- raise notice 'caught numeric_value_out_of_range or cardinality_violation';
- x := -2;
- end;
- return x;
-end$$ language plpgsql;
-select trap_matching_test(50);
- trap_matching_test
---------------------
- 2
-(1 row)
-
-select trap_matching_test(0);
-NOTICE: caught data_exception
- trap_matching_test
---------------------
- -1
-(1 row)
-
-select trap_matching_test(100000);
-NOTICE: caught data_exception
- trap_matching_test
---------------------
- -1
-(1 row)
-
-select trap_matching_test(1);
-NOTICE: caught numeric_value_out_of_range or cardinality_violation
- trap_matching_test
---------------------
- -2
-(1 row)
-
-create temp table foo (f1 int);
-create function subxact_rollback_semantics() returns int as $$
-declare x int;
-begin
- x := 1;
- insert into foo values(x);
- begin
- x := x + 1;
- insert into foo values(x);
- raise exception 'inner';
- exception
- when others then
- x := x * 10;
- end;
- insert into foo values(x);
- return x;
-end$$ language plpgsql;
-select subxact_rollback_semantics();
- subxact_rollback_semantics
-----------------------------
- 20
-(1 row)
-
-select * from foo;
- f1
-----
- 1
- 20
-(2 rows)
-
-drop table foo;
-create function trap_timeout() returns void as $$
-begin
- declare x int;
- begin
- -- we assume this will take longer than 2 seconds:
- select count(*) into x from tenk1 a, tenk1 b, tenk1 c;
- exception
- when others then
- raise notice 'caught others?';
- when query_canceled then
- raise notice 'nyeah nyeah, can''t stop me';
- end;
- -- Abort transaction to abandon the statement_timeout setting. Otherwise,
- -- the next top-level statement would be vulnerable to the timeout.
- raise exception 'end of function';
-end$$ language plpgsql;
-begin;
-set statement_timeout to 2000;
-select trap_timeout();
-NOTICE: nyeah nyeah, can't stop me
-ERROR: end of function
-CONTEXT: PL/pgSQL function trap_timeout() line 15 at RAISE
-rollback;
--- Test for pass-by-ref values being stored in proper context
-create function test_variable_storage() returns text as $$
-declare x text;
-begin
- x := '1234';
- begin
- x := x || '5678';
- -- force error inside subtransaction SPI context
- perform trap_zero_divide(-100);
- exception
- when others then
- x := x || '9012';
- end;
- return x;
-end$$ language plpgsql;
-select test_variable_storage();
-NOTICE: should see this
-NOTICE: should see this only if -100 <> 0
-NOTICE: should see this only if -100 fits in smallint
- test_variable_storage
------------------------
- 123456789012
-(1 row)
-
---
--- test foreign key error trapping
---
-create temp table master(f1 int primary key);
-create temp table slave(f1 int references master deferrable);
-insert into master values(1);
-insert into slave values(1);
-insert into slave values(2); -- fails
-ERROR: insert or update on table "slave" violates foreign key constraint "slave_f1_fkey"
-DETAIL: Key (f1)=(2) is not present in table "master".
-create function trap_foreign_key(int) returns int as $$
-begin
- begin -- start a subtransaction
- insert into slave values($1);
- exception
- when foreign_key_violation then
- raise notice 'caught foreign_key_violation';
- return 0;
- end;
- return 1;
-end$$ language plpgsql;
-create function trap_foreign_key_2() returns int as $$
-begin
- begin -- start a subtransaction
- set constraints all immediate;
- exception
- when foreign_key_violation then
- raise notice 'caught foreign_key_violation';
- return 0;
- end;
- return 1;
-end$$ language plpgsql;
-select trap_foreign_key(1);
- trap_foreign_key
-------------------
- 1
-(1 row)
-
-select trap_foreign_key(2); -- detects FK violation
-NOTICE: caught foreign_key_violation
- trap_foreign_key
-------------------
- 0
-(1 row)
-
-begin;
- set constraints all deferred;
- select trap_foreign_key(2); -- should not detect FK violation
- trap_foreign_key
-------------------
- 1
-(1 row)
-
- savepoint x;
- set constraints all immediate; -- fails
-ERROR: insert or update on table "slave" violates foreign key constraint "slave_f1_fkey"
-DETAIL: Key (f1)=(2) is not present in table "master".
- rollback to x;
- select trap_foreign_key_2(); -- detects FK violation
-NOTICE: caught foreign_key_violation
- trap_foreign_key_2
---------------------
- 0
-(1 row)
-
-commit; -- still fails
-ERROR: insert or update on table "slave" violates foreign key constraint "slave_f1_fkey"
-DETAIL: Key (f1)=(2) is not present in table "master".
-drop function trap_foreign_key(int);
-drop function trap_foreign_key_2();
---
-- Test proper snapshot handling in simple expressions
--
create temp table users(login text, id serial);
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
index 91e2647..7ae3263 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -66,9 +66,6 @@ CREATE INDEX quad_poly_tbl_idx ON quad_poly_tbl USING spgist(p);
SET enable_seqscan = ON;
SET enable_indexscan = OFF;
SET enable_bitmapscan = OFF;
-CREATE TABLE quad_poly_tbl_ord_seq1 AS
-SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
-FROM quad_poly_tbl;
CREATE TABLE quad_poly_tbl_ord_seq2 AS
SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
@@ -285,28 +282,6 @@ SET enable_indexscan = ON;
SET enable_bitmapscan = OFF;
EXPLAIN (COSTS OFF)
SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
-FROM quad_poly_tbl;
- QUERY PLAN
------------------------------------------------------------
- WindowAgg
- -> Index Scan using quad_poly_tbl_idx on quad_poly_tbl
- Order By: (p <-> '(123,456)'::point)
-(3 rows)
-
-CREATE TEMP TABLE quad_poly_tbl_ord_idx1 AS
-SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
-FROM quad_poly_tbl;
-SELECT *
-FROM quad_poly_tbl_ord_seq1 seq FULL JOIN quad_poly_tbl_ord_idx1 idx
- ON seq.n = idx.n AND seq.id = idx.id AND
- (seq.dist = idx.dist OR seq.dist IS NULL AND idx.dist IS NULL)
-WHERE seq.id IS NULL OR idx.id IS NULL;
- n | dist | id | n | dist | id
----+------+----+---+------+----
-(0 rows)
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
QUERY PLAN
---------------------------------------------------------------------------------
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 4638374..2f048f3 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1282,7 +1282,9 @@ drop table cchild;
--
-- temporarily disable fancy output, so view changes create less diff noise
\a\t
-SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
+SELECT viewname, definition FROM pg_views
+WHERE schemaname IN ('pg_catalog', 'public')
+ORDER BY viewname;
iexit| SELECT ih.name,
ih.thepath,
interpt_pp(ih.thepath, r.thepath) AS exit
@@ -2418,7 +2420,8 @@ toyemp| SELECT emp.name,
(12 * emp.salary) AS annualsal
FROM emp;
SELECT tablename, rulename, definition FROM pg_rules
- ORDER BY tablename, rulename;
+WHERE schemaname IN ('pg_catalog', 'public')
+ORDER BY tablename, rulename;
pg_settings|pg_settings_n|CREATE RULE pg_settings_n AS
ON UPDATE TO pg_catalog.pg_settings DO INSTEAD NOTHING;
pg_settings|pg_settings_u|CREATE RULE pg_settings_u AS
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 29682e3..8882a07 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -38,7 +38,6 @@ d_star|f
date_tbl|f
default_tbl|f
defaultexpr_tbl|f
-delete_test_table|t
dept|f
dupindexcols|t
e_star|f
@@ -167,7 +166,6 @@ polygon_tbl|t
quad_box_tbl|t
quad_point_tbl|t
quad_poly_tbl|t
-quad_poly_tbl_ord_seq1|f
quad_poly_tbl_ord_seq2|f
radix_text_tbl|t
ramp|f
@@ -209,6 +207,7 @@ time_tbl|f
timestamp_tbl|f
timestamptz_tbl|f
timetz_tbl|f
+tmp|f
varchar_tbl|f
view_base_table|t
-- restore normal output mode
diff --git a/src/test/regress/input/constraints.source b/src/test/regress/input/constraints.source
index 98dd421..0abf955 100644
--- a/src/test/regress/input/constraints.source
+++ b/src/test/regress/input/constraints.source
@@ -201,7 +201,7 @@ DELETE FROM INSERT_TBL;
ALTER SEQUENCE INSERT_SEQ RESTART WITH 4;
-CREATE TABLE tmp (xd INT, yd TEXT, zd INT);
+CREATE TEMP TABLE tmp (xd INT, yd TEXT, zd INT);
INSERT INTO tmp VALUES (null, 'Y', null);
INSERT INTO tmp VALUES (5, '!check failed', null);
diff --git a/src/test/regress/output/constraints.source b/src/test/regress/output/constraints.source
index e838906..465d6da 100644
--- a/src/test/regress/output/constraints.source
+++ b/src/test/regress/output/constraints.source
@@ -291,7 +291,7 @@ NOTICE: drop cascades to table atacc2
--
DELETE FROM INSERT_TBL;
ALTER SEQUENCE INSERT_SEQ RESTART WITH 4;
-CREATE TABLE tmp (xd INT, yd TEXT, zd INT);
+CREATE TEMP TABLE tmp (xd INT, yd TEXT, zd INT);
INSERT INTO tmp VALUES (null, 'Y', null);
INSERT INTO tmp VALUES (5, '!check failed', null);
INSERT INTO tmp VALUES (null, 'try again', null);
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index f320fb6..39018ed 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -15,15 +15,12 @@ test: tablespace
# ----------
test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum money rangetypes pg_lsn regproc
-# Depends on things setup during char, varchar and text
-test: strings
-# Depends on int2, int4, int8, float4, float8
-test: numerology
-
# ----------
# The second group of parallel tests
+# strings depends on char, varchar and text
+# numerology depends on int2, int4, int8, float4, float8
# ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval inet macaddr macaddr8 tstypes fsm
+test: strings numerology point lseg line box path polygon circle date time timetz timestamp timestamptz interval inet macaddr macaddr8 tstypes fsm
# ----------
# Another group of parallel tests
@@ -35,8 +32,6 @@ test: geometry horology regex oidjoins type_sanity opr_sanity misc_sanity commen
# ----------
# These four each depend on the previous one
# ----------
-test: insert
-test: insert_conflict
test: create_function_1
test: create_type
test: create_table
@@ -48,19 +43,19 @@ test: create_function_2
# execute two copy tests parallel, to check that copy itself
# is concurrent safe.
# ----------
-test: copy copyselect copydml
+test: copy copyselect copydml insert insert_conflict
# ----------
# More groups of parallel tests
# ----------
test: create_misc create_operator create_procedure
-# These depend on the above two
-test: create_index create_view index_including index_including_gist
+# These depend on create_misc and create_operator
+test: create_index create_index_spgist create_view index_including index_including_gist
# ----------
# Another group of parallel tests
# ----------
-test: create_aggregate create_function_3 create_cast constraints triggers inherit typed_table vacuum drop_if_exists updatable_views rolenames roleattributes create_am hash_func
+test: create_aggregate create_function_3 create_cast constraints triggers select inherit typed_table vacuum drop_if_exists updatable_views rolenames roleattributes create_am hash_func errors
# ----------
# sanity_check does a vacuum, affecting the sort order of SELECT *
@@ -69,30 +64,25 @@ test: create_aggregate create_function_3 create_cast constraints triggers inheri
test: sanity_check
# ----------
-# Believe it or not, select creates a table, subsequent
-# tests need.
-# ----------
-test: errors
-test: select
-ignore: random
-
-# ----------
# Another group of parallel tests
+# Note: the ignore: line does not run random, just mark it as ignorable
# ----------
+ignore: random
test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete
# ----------
# Another group of parallel tests
# ----------
-test: brin gin gist spgist privileges init_privs security_label collate matview lock replica_identity rowsecurity object_address tablesample groupingsets drop_operator password identity generated
+test: brin gin gist spgist privileges init_privs security_label join_hash collate matview lock replica_identity rowsecurity object_address tablesample groupingsets drop_operator password identity generated
# ----------
# Another group of parallel tests
# ----------
-test: create_table_like alter_generic alter_operator misc psql async dbsize misc_functions sysviews tsrf tidscan stats_ext
+test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tidscan
-# rules cannot run concurrently with any test that creates a view
-test: rules psql_crosstab amutils
+# rules cannot run concurrently with any test that creates
+# a view or rule in the public schema
+test: rules psql psql_crosstab amutils stats_ext
# run by itself so it can run parallel workers
test: select_parallel
@@ -121,7 +111,7 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion tr
# ----------
# Another group of parallel tests
# ----------
-test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info
+test: partition_join partition_prune reloptions hash_part indexing index_fastpath partition_aggregate partition_info
# event triggers cannot run concurrently with any test that runs DDL
test: event_trigger
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 36644aa..e561e9b 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -50,8 +50,6 @@ test: opr_sanity
test: misc_sanity
test: comments
test: expressions
-test: insert
-test: insert_conflict
test: create_function_1
test: create_type
test: create_table
@@ -59,18 +57,22 @@ test: create_function_2
test: copy
test: copyselect
test: copydml
+test: insert
+test: insert_conflict
test: create_misc
test: create_operator
test: create_procedure
test: create_index
+test: create_index_spgist
+test: create_view
test: index_including
test: index_including_gist
-test: create_view
test: create_aggregate
test: create_function_3
test: create_cast
test: constraints
test: triggers
+test: select
test: inherit
test: typed_table
test: vacuum
@@ -80,9 +82,8 @@ test: rolenames
test: roleattributes
test: create_am
test: hash_func
-test: sanity_check
test: errors
-test: select
+test: sanity_check
test: select_into
test: select_distinct
test: select_distinct_on
@@ -111,6 +112,7 @@ test: spgist
test: privileges
test: init_privs
test: security_label
+test: join_hash
test: collate
test: matview
test: lock
@@ -127,21 +129,21 @@ test: create_table_like
test: alter_generic
test: alter_operator
test: misc
-test: psql
test: async
test: dbsize
test: misc_functions
test: sysviews
test: tsrf
test: tidscan
-test: stats_ext
test: rules
+test: psql
test: psql_crosstab
+test: amutils
+test: stats_ext
test: select_parallel
test: write_parallel
test: publication
test: subscription
-test: amutils
test: select_views
test: portals_p2
test: foreign_key
@@ -157,14 +159,14 @@ test: window
test: xmlmap
test: functional_deps
test: advisory_lock
+test: indirect_toast
+test: equivclass
test: json
test: jsonb
test: json_encoding
test: jsonpath
test: jsonpath_encoding
test: jsonb_jsonpath
-test: indirect_toast
-test: equivclass
test: plancache
test: limit
test: plpgsql
@@ -188,6 +190,7 @@ test: partition_prune
test: reloptions
test: hash_part
test: indexing
+test: index_fastpath
test: partition_aggregate
test: partition_info
test: event_trigger
diff --git a/src/test/regress/sql/btree_index.sql b/src/test/regress/sql/btree_index.sql
index 19fbfa8..48eaf4f 100644
--- a/src/test/regress/sql/btree_index.sql
+++ b/src/test/regress/sql/btree_index.sql
@@ -120,3 +120,23 @@ create index btree_idx_err on btree_test(a) with (vacuum_cleanup_index_scale_fac
-- Simple ALTER INDEX
alter index btree_idx1 set (vacuum_cleanup_index_scale_factor = 70.0);
select reloptions from pg_class WHERE oid = 'btree_idx1'::regclass;
+
+--
+-- Test for multilevel page deletion
+--
+CREATE TABLE delete_test_table (a bigint, b bigint, c bigint, d bigint);
+INSERT INTO delete_test_table SELECT i, 1, 2, 3 FROM generate_series(1,80000) i;
+ALTER TABLE delete_test_table ADD PRIMARY KEY (a,b,c,d);
+-- Delete most entries, and vacuum, deleting internal pages and creating "fast
+-- root"
+DELETE FROM delete_test_table WHERE a < 79990;
+VACUUM delete_test_table;
+
+--
+-- Test B-tree insertion with a metapage update (XLOG_BTREE_INSERT_META
+-- WAL record type). This happens when a "fast root" page is split. This
+-- also creates coverage for nbtree FSM page recycling.
+--
+-- The vacuum above should've turned the leaf page into a fast root. We just
+-- need to insert some rows to cause the fast root page to split.
+INSERT INTO delete_test_table SELECT i, 1, 2, 3 FROM generate_series(1,1000) i;
diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql
index 4d2535b..2f0e9a6 100644
--- a/src/test/regress/sql/create_index.sql
+++ b/src/test/regress/sql/create_index.sql
@@ -97,35 +97,7 @@ CREATE INDEX ggpolygonind ON gpolygon_tbl USING gist (f1);
CREATE INDEX ggcircleind ON gcircle_tbl USING gist (f1);
--
--- SP-GiST
---
-
-CREATE TABLE quad_point_tbl AS
- SELECT point(unique1,unique2) AS p FROM tenk1;
-
-INSERT INTO quad_point_tbl
- SELECT '(333.0,400.0)'::point FROM generate_series(1,1000);
-
-INSERT INTO quad_point_tbl VALUES (NULL), (NULL), (NULL);
-
-CREATE INDEX sp_quad_ind ON quad_point_tbl USING spgist (p);
-
-CREATE TABLE kd_point_tbl AS SELECT * FROM quad_point_tbl;
-
-CREATE INDEX sp_kd_ind ON kd_point_tbl USING spgist (p kd_point_ops);
-
-CREATE TABLE radix_text_tbl AS
- SELECT name AS t FROM road WHERE name !~ '^[0-9]';
-
-INSERT INTO radix_text_tbl
- SELECT 'P0123456789abcdef' FROM generate_series(1,1000);
-INSERT INTO radix_text_tbl VALUES ('P0123456789abcde');
-INSERT INTO radix_text_tbl VALUES ('P0123456789abcdefF');
-
-CREATE INDEX sp_radix_ind ON radix_text_tbl USING spgist (t);
-
---
--- Test GiST and SP-GiST indexes
+-- Test GiST indexes
--
-- get non-indexed results for comparison purposes
@@ -178,66 +150,6 @@ SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
-
-SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
-
-SELECT count(*) FROM quad_point_tbl;
-
-SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-
-SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
-
-SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
-
-SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
-
-SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
-
-SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
-
-SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
-
-CREATE TEMP TABLE quad_point_tbl_ord_seq1 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl;
-
-CREATE TEMP TABLE quad_point_tbl_ord_seq2 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-
-CREATE TEMP TABLE quad_point_tbl_ord_seq3 AS
-SELECT rank() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
-FROM quad_point_tbl WHERE p IS NOT NULL;
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
-
-SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
-
-SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
-
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
-
-SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
-
-SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
-
-SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
-
-SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
-
SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10;
SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10;
@@ -336,196 +248,6 @@ SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0
SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
-SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
-SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl;
-SELECT count(*) FROM quad_point_tbl;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
-SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
-SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
-SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
-SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
-SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
-SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl;
-CREATE TEMP TABLE quad_point_tbl_ord_idx1 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl;
-SELECT * FROM quad_point_tbl_ord_seq1 seq FULL JOIN quad_point_tbl_ord_idx1 idx
-ON seq.n = idx.n
-AND (seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-CREATE TEMP TABLE quad_point_tbl_ord_idx2 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-SELECT * FROM quad_point_tbl_ord_seq2 seq FULL JOIN quad_point_tbl_ord_idx2 idx
-ON seq.n = idx.n
-AND (seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
-FROM quad_point_tbl WHERE p IS NOT NULL;
-CREATE TEMP TABLE quad_point_tbl_ord_idx3 AS
-SELECT rank() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
-FROM quad_point_tbl WHERE p IS NOT NULL;
-SELECT * FROM quad_point_tbl_ord_seq3 seq FULL JOIN quad_point_tbl_ord_idx3 idx
-ON seq.n = idx.n
-AND (seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
-SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
-SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
-SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
-SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
-SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
-SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM kd_point_tbl;
-CREATE TEMP TABLE kd_point_tbl_ord_idx1 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM kd_point_tbl;
-SELECT * FROM quad_point_tbl_ord_seq1 seq FULL JOIN kd_point_tbl_ord_idx1 idx
-ON seq.n = idx.n AND
-(seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-CREATE TEMP TABLE kd_point_tbl_ord_idx2 AS
-SELECT rank() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
-FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-SELECT * FROM quad_point_tbl_ord_seq2 seq FULL JOIN kd_point_tbl_ord_idx2 idx
-ON seq.n = idx.n AND
-(seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
-FROM kd_point_tbl WHERE p IS NOT NULL;
-CREATE TEMP TABLE kd_point_tbl_ord_idx3 AS
-SELECT rank() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
-FROM kd_point_tbl WHERE p IS NOT NULL;
-SELECT * FROM quad_point_tbl_ord_seq3 seq FULL JOIN kd_point_tbl_ord_idx3 idx
-ON seq.n = idx.n AND
-(seq.dist = idx.dist AND seq.p ~= idx.p OR seq.p IS NULL AND idx.p IS NULL)
-WHERE seq.n IS NULL OR idx.n IS NULL;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
-SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
-SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
-SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
-SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
-SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
-SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
-SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
-SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
-SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
-
-EXPLAIN (COSTS OFF)
SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10;
SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10;
@@ -542,130 +264,6 @@ EXPLAIN (COSTS OFF)
SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
-SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
-SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl;
-SELECT count(*) FROM quad_point_tbl;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
-SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
-SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
-SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
-SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
-SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
-SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
-SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
-SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
-SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
-SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
-SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
-SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
-SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
-SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
-SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
-SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
-SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
-SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
-SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
-SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
-SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
-SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
-
-EXPLAIN (COSTS OFF)
-SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
-SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
-
RESET enable_seqscan;
RESET enable_indexscan;
RESET enable_bitmapscan;
@@ -1141,26 +739,6 @@ explain (costs off)
select * from boolindex where b is false order by i desc limit 10;
--
--- Test for multilevel page deletion
---
-CREATE TABLE delete_test_table (a bigint, b bigint, c bigint, d bigint);
-INSERT INTO delete_test_table SELECT i, 1, 2, 3 FROM generate_series(1,80000) i;
-ALTER TABLE delete_test_table ADD PRIMARY KEY (a,b,c,d);
--- Delete most entries, and vacuum, deleting internal pages and creating "fast
--- root"
-DELETE FROM delete_test_table WHERE a < 79990;
-VACUUM delete_test_table;
-
---
--- Test B-tree insertion with a metapage update (XLOG_BTREE_INSERT_META
--- WAL record type). This happens when a "fast root" page is split. This
--- also creates coverage for nbtree FSM page recycling.
---
--- The vacuum above should've turned the leaf page into a fast root. We just
--- need to insert some rows to cause the fast root page to split.
-INSERT INTO delete_test_table SELECT i, 1, 2, 3 FROM generate_series(1,1000) i;
-
---
-- REINDEX (VERBOSE)
--
CREATE TABLE reindex_verbose(id integer primary key);
diff --git a/src/test/regress/sql/create_index_spgist.sql b/src/test/regress/sql/create_index_spgist.sql
new file mode 100644
index 0000000..8e6c453
--- /dev/null
+++ b/src/test/regress/sql/create_index_spgist.sql
@@ -0,0 +1,415 @@
+--
+-- SP-GiST index tests
+--
+
+CREATE TABLE quad_point_tbl AS
+ SELECT point(unique1,unique2) AS p FROM tenk1;
+
+INSERT INTO quad_point_tbl
+ SELECT '(333.0,400.0)'::point FROM generate_series(1,1000);
+
+INSERT INTO quad_point_tbl VALUES (NULL), (NULL), (NULL);
+
+CREATE INDEX sp_quad_ind ON quad_point_tbl USING spgist (p);
+
+CREATE TABLE kd_point_tbl AS SELECT * FROM quad_point_tbl;
+
+CREATE INDEX sp_kd_ind ON kd_point_tbl USING spgist (p kd_point_ops);
+
+CREATE TABLE radix_text_tbl AS
+ SELECT name AS t FROM road WHERE name !~ '^[0-9]';
+
+INSERT INTO radix_text_tbl
+ SELECT 'P0123456789abcdef' FROM generate_series(1,1000);
+INSERT INTO radix_text_tbl VALUES ('P0123456789abcde');
+INSERT INTO radix_text_tbl VALUES ('P0123456789abcdefF');
+
+CREATE INDEX sp_radix_ind ON radix_text_tbl USING spgist (t);
+
+-- get non-indexed results for comparison purposes
+
+SET enable_seqscan = ON;
+SET enable_indexscan = OFF;
+SET enable_bitmapscan = OFF;
+
+SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
+
+SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
+
+SELECT count(*) FROM quad_point_tbl;
+
+SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+
+SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+
+SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
+
+SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
+
+SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
+
+SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
+
+SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
+
+CREATE TEMP TABLE quad_point_tbl_ord_seq1 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl;
+
+CREATE TEMP TABLE quad_point_tbl_ord_seq2 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+
+CREATE TEMP TABLE quad_point_tbl_ord_seq3 AS
+SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
+FROM quad_point_tbl WHERE p IS NOT NULL;
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+
+SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
+
+SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
+
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
+
+SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
+
+SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
+
+SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
+
+SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
+
+-- Now check the results from plain indexscan
+SET enable_seqscan = OFF;
+SET enable_indexscan = ON;
+SET enable_bitmapscan = OFF;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
+SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
+SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl;
+SELECT count(*) FROM quad_point_tbl;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
+SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
+SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
+SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
+SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
+SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl;
+CREATE TEMP TABLE quad_point_tbl_ord_idx1 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl;
+SELECT * FROM quad_point_tbl_ord_seq1 seq FULL JOIN quad_point_tbl_ord_idx1 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+CREATE TEMP TABLE quad_point_tbl_ord_idx2 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+SELECT * FROM quad_point_tbl_ord_seq2 seq FULL JOIN quad_point_tbl_ord_idx2 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
+FROM quad_point_tbl WHERE p IS NOT NULL;
+CREATE TEMP TABLE quad_point_tbl_ord_idx3 AS
+SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
+FROM quad_point_tbl WHERE p IS NOT NULL;
+SELECT * FROM quad_point_tbl_ord_seq3 seq FULL JOIN quad_point_tbl_ord_idx3 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
+SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
+SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
+SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
+SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
+SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM kd_point_tbl;
+CREATE TEMP TABLE kd_point_tbl_ord_idx1 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM kd_point_tbl;
+SELECT * FROM quad_point_tbl_ord_seq1 seq FULL JOIN kd_point_tbl_ord_idx1 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+CREATE TEMP TABLE kd_point_tbl_ord_idx2 AS
+SELECT row_number() OVER (ORDER BY p <-> '0,0') n, p <-> '0,0' dist, p
+FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+SELECT * FROM quad_point_tbl_ord_seq2 seq FULL JOIN kd_point_tbl_ord_idx2 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+
+EXPLAIN (COSTS OFF)
+SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
+FROM kd_point_tbl WHERE p IS NOT NULL;
+CREATE TEMP TABLE kd_point_tbl_ord_idx3 AS
+SELECT row_number() OVER (ORDER BY p <-> '333,400') n, p <-> '333,400' dist, p
+FROM kd_point_tbl WHERE p IS NOT NULL;
+SELECT * FROM quad_point_tbl_ord_seq3 seq FULL JOIN kd_point_tbl_ord_idx3 idx
+ON seq.n = idx.n
+WHERE seq.dist IS DISTINCT FROM idx.dist;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
+SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
+SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
+SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
+SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
+SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
+SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
+SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
+SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
+SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
+
+-- Now check the results from bitmap indexscan
+SET enable_seqscan = OFF;
+SET enable_indexscan = OFF;
+SET enable_bitmapscan = ON;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
+SELECT count(*) FROM quad_point_tbl WHERE p IS NULL;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
+SELECT count(*) FROM quad_point_tbl WHERE p IS NOT NULL;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl;
+SELECT count(*) FROM quad_point_tbl;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
+SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
+SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
+SELECT count(*) FROM quad_point_tbl WHERE p <^ '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
+SELECT count(*) FROM quad_point_tbl WHERE p >^ '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
+SELECT count(*) FROM quad_point_tbl WHERE p ~= '(4585, 365)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+SELECT count(*) FROM kd_point_tbl WHERE p <@ box '(200,200,1000,1000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+SELECT count(*) FROM kd_point_tbl WHERE box '(200,200,1000,1000)' @> p;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
+SELECT count(*) FROM kd_point_tbl WHERE p << '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
+SELECT count(*) FROM kd_point_tbl WHERE p >> '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
+SELECT count(*) FROM kd_point_tbl WHERE p <^ '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
+SELECT count(*) FROM kd_point_tbl WHERE p >^ '(5000, 4000)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
+SELECT count(*) FROM kd_point_tbl WHERE p ~= '(4585, 365)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdef';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcde';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+SELECT count(*) FROM radix_text_tbl WHERE t = 'P0123456789abcdefF';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
+SELECT count(*) FROM radix_text_tbl WHERE t < 'Aztec Ct ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
+SELECT count(*) FROM radix_text_tbl WHERE t ~<~ 'Aztec Ct ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
+SELECT count(*) FROM radix_text_tbl WHERE t <= 'Aztec Ct ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
+SELECT count(*) FROM radix_text_tbl WHERE t ~<=~ 'Aztec Ct ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Aztec Ct ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
+SELECT count(*) FROM radix_text_tbl WHERE t = 'Worth St ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
+SELECT count(*) FROM radix_text_tbl WHERE t >= 'Worth St ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
+SELECT count(*) FROM radix_text_tbl WHERE t ~>=~ 'Worth St ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
+SELECT count(*) FROM radix_text_tbl WHERE t > 'Worth St ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
+SELECT count(*) FROM radix_text_tbl WHERE t ~>~ 'Worth St ';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
+SELECT count(*) FROM radix_text_tbl WHERE t ^@ 'Worth';
+
+RESET enable_seqscan;
+RESET enable_indexscan;
+RESET enable_bitmapscan;
diff --git a/src/test/regress/sql/index_fastpath.sql b/src/test/regress/sql/index_fastpath.sql
new file mode 100644
index 0000000..38bba29
--- /dev/null
+++ b/src/test/regress/sql/index_fastpath.sql
@@ -0,0 +1,113 @@
+-- test fastpath mechanism for index insertion
+create table fastpath (a int, b text, c numeric);
+create unique index fpindex1 on fastpath(a);
+
+insert into fastpath values (1, 'b1', 100.00);
+insert into fastpath values (1, 'b1', 100.00); -- unique key check
+
+truncate fastpath;
+insert into fastpath select generate_series(1,10000), 'b', 100;
+
+-- vacuum the table so as to improve chances of index-only scans. we can't
+-- guarantee if index-only scans will be picked up in all cases or not, but
+-- that fuzziness actually helps the test.
+vacuum fastpath;
+
+set enable_seqscan to false;
+set enable_bitmapscan to false;
+
+select sum(a) from fastpath where a = 6456;
+select sum(a) from fastpath where a >= 5000 and a < 5700;
+
+-- drop the only index on the table and compute hashes for
+-- a few queries which orders the results in various different ways.
+drop index fpindex1;
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+
+-- now create a multi-column index with both column asc
+create index fpindex2 on fastpath(a, b);
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+-- again, vacuum here either forces index-only scans or creates fuzziness
+vacuum fastpath;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+
+-- same queries with a different kind of index now. the final result must not
+-- change irrespective of what kind of index we have.
+drop index fpindex2;
+create index fpindex3 on fastpath(a desc, b asc);
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+vacuum fastpath;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+
+-- repeat again
+drop index fpindex3;
+create index fpindex4 on fastpath(a asc, b desc);
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+vacuum fastpath;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+
+-- and again, this time indexing by (b, a). Note that column "b" has non-unique
+-- values.
+drop index fpindex4;
+create index fpindex5 on fastpath(b asc, a desc);
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+vacuum fastpath;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+
+-- one last time
+drop index fpindex5;
+create index fpindex6 on fastpath(b desc, a desc);
+truncate fastpath;
+insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
+vacuum fastpath;
+select md5(string_agg(a::text, b order by a, b asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a desc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+select md5(string_agg(a::text, b order by b, a asc)) from fastpath
+ where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
+
+drop table fastpath;
diff --git a/src/test/regress/sql/indexing.sql b/src/test/regress/sql/indexing.sql
index 954632b..7d46e03 100644
--- a/src/test/regress/sql/indexing.sql
+++ b/src/test/regress/sql/indexing.sql
@@ -620,120 +620,6 @@ insert into idxpart values (857142, 'six');
select tableoid::regclass, * from idxpart order by a;
drop table idxpart;
--- test fastpath mechanism for index insertion
-create table fastpath (a int, b text, c numeric);
-create unique index fpindex1 on fastpath(a);
-
-insert into fastpath values (1, 'b1', 100.00);
-insert into fastpath values (1, 'b1', 100.00); -- unique key check
-
-truncate fastpath;
-insert into fastpath select generate_series(1,10000), 'b', 100;
-
--- vacuum the table so as to improve chances of index-only scans. we can't
--- guarantee if index-only scans will be picked up in all cases or not, but
--- that fuzziness actually helps the test.
-vacuum fastpath;
-
-set enable_seqscan to false;
-set enable_bitmapscan to false;
-
-select sum(a) from fastpath where a = 6456;
-select sum(a) from fastpath where a >= 5000 and a < 5700;
-
--- drop the only index on the table and compute hashes for
--- a few queries which orders the results in various different ways.
-drop index fpindex1;
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-
--- now create a multi-column index with both column asc
-create index fpindex2 on fastpath(a, b);
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
--- again, vacuum here either forces index-only scans or creates fuzziness
-vacuum fastpath;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-
--- same queries with a different kind of index now. the final result must not
--- change irrespective of what kind of index we have.
-drop index fpindex2;
-create index fpindex3 on fastpath(a desc, b asc);
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
-vacuum fastpath;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-
--- repeat again
-drop index fpindex3;
-create index fpindex4 on fastpath(a asc, b desc);
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
-vacuum fastpath;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-
--- and again, this time indexing by (b, a). Note that column "b" has non-unique
--- values.
-drop index fpindex4;
-create index fpindex5 on fastpath(b asc, a desc);
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
-vacuum fastpath;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-
--- one last time
-drop index fpindex5;
-create index fpindex6 on fastpath(b desc, a desc);
-truncate fastpath;
-insert into fastpath select y.x, 'b' || (y.x/10)::text, 100 from (select generate_series(1,10000) as x) y;
-vacuum fastpath;
-select md5(string_agg(a::text, b order by a, b asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by a desc, b desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a desc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-select md5(string_agg(a::text, b order by b, a asc)) from fastpath
- where a >= 1000 and a < 2000 and b > 'b1' and b < 'b3';
-
-drop table fastpath;
-
-- intentionally leave some objects around
create table idxpart (a int) partition by range (a);
create table idxpart1 partition of idxpart for values from (0) to (100);
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index c247509..bf6d5c3 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -2067,473 +2067,3 @@ where exists (select 1 from j3
and t1.unique1 < 1;
drop table j3;
-
---
--- exercises for the hash join code
---
-
-begin;
-
-set local min_parallel_table_scan_size = 0;
-set local parallel_setup_cost = 0;
-
--- Extract bucket and batch counts from an explain analyze plan. In
--- general we can't make assertions about how many batches (or
--- buckets) will be required because it can vary, but we can in some
--- special cases and we can check for growth.
-create or replace function find_hash(node json)
-returns json language plpgsql
-as
-$$
-declare
- x json;
- child json;
-begin
- if node->>'Node Type' = 'Hash' then
- return node;
- else
- for child in select json_array_elements(node->'Plans')
- loop
- x := find_hash(child);
- if x is not null then
- return x;
- end if;
- end loop;
- return null;
- end if;
-end;
-$$;
-create or replace function hash_join_batches(query text)
-returns table (original int, final int) language plpgsql
-as
-$$
-declare
- whole_plan json;
- hash_node json;
-begin
- for whole_plan in
- execute 'explain (analyze, format ''json'') ' || query
- loop
- hash_node := find_hash(json_extract_path(whole_plan, '0', 'Plan'));
- original := hash_node->>'Original Hash Batches';
- final := hash_node->>'Hash Batches';
- return next;
- end loop;
-end;
-$$;
-
--- Make a simple relation with well distributed keys and correctly
--- estimated size.
-create table simple as
- select generate_series(1, 20000) AS id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
-alter table simple set (parallel_workers = 2);
-analyze simple;
-
--- Make a relation whose size we will under-estimate. We want stats
--- to say 1000 rows, but actually there are 20,000 rows.
-create table bigger_than_it_looks as
- select generate_series(1, 20000) as id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
-alter table bigger_than_it_looks set (autovacuum_enabled = 'false');
-alter table bigger_than_it_looks set (parallel_workers = 2);
-analyze bigger_than_it_looks;
-update pg_class set reltuples = 1000 where relname = 'bigger_than_it_looks';
-
--- Make a relation whose size we underestimate and that also has a
--- kind of skew that breaks our batching scheme. We want stats to say
--- 2 rows, but actually there are 20,000 rows with the same key.
-create table extremely_skewed (id int, t text);
-alter table extremely_skewed set (autovacuum_enabled = 'false');
-alter table extremely_skewed set (parallel_workers = 2);
-analyze extremely_skewed;
-insert into extremely_skewed
- select 42 as id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
- from generate_series(1, 20000);
-update pg_class
- set reltuples = 2, relpages = pg_relation_size('extremely_skewed') / 8192
- where relname = 'extremely_skewed';
-
--- Make a relation with a couple of enormous tuples.
-create table wide as select generate_series(1, 2) as id, rpad('', 320000, 'x') as t;
-alter table wide set (parallel_workers = 2);
-
--- The "optimal" case: the hash table fits in memory; we plan for 1
--- batch, we stick to that number, and peak memory usage stays within
--- our work_mem budget
-
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-set local work_mem = '4MB';
-explain (costs off)
- select count(*) from simple r join simple s using (id);
-select count(*) from simple r join simple s using (id);
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
-rollback to settings;
-
--- parallel with parallel-oblivious hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '4MB';
-set local enable_parallel_hash = off;
-explain (costs off)
- select count(*) from simple r join simple s using (id);
-select count(*) from simple r join simple s using (id);
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
-rollback to settings;
-
--- parallel with parallel-aware hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '4MB';
-set local enable_parallel_hash = on;
-explain (costs off)
- select count(*) from simple r join simple s using (id);
-select count(*) from simple r join simple s using (id);
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
-rollback to settings;
-
--- The "good" case: batches required, but we plan the right number; we
--- plan for some number of batches, and we stick to that number, and
--- peak memory usage says within our work_mem budget
-
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-set local work_mem = '128kB';
-explain (costs off)
- select count(*) from simple r join simple s using (id);
-select count(*) from simple r join simple s using (id);
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
-rollback to settings;
-
--- parallel with parallel-oblivious hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '128kB';
-set local enable_parallel_hash = off;
-explain (costs off)
- select count(*) from simple r join simple s using (id);
-select count(*) from simple r join simple s using (id);
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
-rollback to settings;
-
--- parallel with parallel-aware hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '192kB';
-set local enable_parallel_hash = on;
-explain (costs off)
- select count(*) from simple r join simple s using (id);
-select count(*) from simple r join simple s using (id);
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
-rollback to settings;
-
--- The "bad" case: during execution we need to increase number of
--- batches; in this case we plan for 1 batch, and increase at least a
--- couple of times, and peak memory usage stays within our work_mem
--- budget
-
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-set local work_mem = '128kB';
-explain (costs off)
- select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
-select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
-$$);
-rollback to settings;
-
--- parallel with parallel-oblivious hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '128kB';
-set local enable_parallel_hash = off;
-explain (costs off)
- select count(*) from simple r join bigger_than_it_looks s using (id);
-select count(*) from simple r join bigger_than_it_looks s using (id);
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join bigger_than_it_looks s using (id);
-$$);
-rollback to settings;
-
--- parallel with parallel-aware hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 1;
-set local work_mem = '192kB';
-set local enable_parallel_hash = on;
-explain (costs off)
- select count(*) from simple r join bigger_than_it_looks s using (id);
-select count(*) from simple r join bigger_than_it_looks s using (id);
-select original > 1 as initially_multibatch, final > original as increased_batches
- from hash_join_batches(
-$$
- select count(*) from simple r join bigger_than_it_looks s using (id);
-$$);
-rollback to settings;
-
--- The "ugly" case: increasing the number of batches during execution
--- doesn't help, so stop trying to fit in work_mem and hope for the
--- best; in this case we plan for 1 batch, increases just once and
--- then stop increasing because that didn't help at all, so we blow
--- right through the work_mem budget and hope for the best...
-
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-set local work_mem = '128kB';
-explain (costs off)
- select count(*) from simple r join extremely_skewed s using (id);
-select count(*) from simple r join extremely_skewed s using (id);
-select * from hash_join_batches(
-$$
- select count(*) from simple r join extremely_skewed s using (id);
-$$);
-rollback to settings;
-
--- parallel with parallel-oblivious hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '128kB';
-set local enable_parallel_hash = off;
-explain (costs off)
- select count(*) from simple r join extremely_skewed s using (id);
-select count(*) from simple r join extremely_skewed s using (id);
-select * from hash_join_batches(
-$$
- select count(*) from simple r join extremely_skewed s using (id);
-$$);
-rollback to settings;
-
--- parallel with parallel-aware hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 1;
-set local work_mem = '128kB';
-set local enable_parallel_hash = on;
-explain (costs off)
- select count(*) from simple r join extremely_skewed s using (id);
-select count(*) from simple r join extremely_skewed s using (id);
-select * from hash_join_batches(
-$$
- select count(*) from simple r join extremely_skewed s using (id);
-$$);
-rollback to settings;
-
--- A couple of other hash join tests unrelated to work_mem management.
-
--- Check that EXPLAIN ANALYZE has data even if the leader doesn't participate
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-set local work_mem = '4MB';
-set local parallel_leader_participation = off;
-select * from hash_join_batches(
-$$
- select count(*) from simple r join simple s using (id);
-$$);
-rollback to settings;
-
--- Exercise rescans. We'll turn off parallel_leader_participation so
--- that we can check that instrumentation comes back correctly.
-
-create table join_foo as select generate_series(1, 3) as id, 'xxxxx'::text as t;
-alter table join_foo set (parallel_workers = 0);
-create table join_bar as select generate_series(1, 10000) as id, 'xxxxx'::text as t;
-alter table join_bar set (parallel_workers = 2);
-
--- multi-batch with rescan, parallel-oblivious
-savepoint settings;
-set enable_parallel_hash = off;
-set parallel_leader_participation = off;
-set min_parallel_table_scan_size = 0;
-set parallel_setup_cost = 0;
-set parallel_tuple_cost = 0;
-set max_parallel_workers_per_gather = 2;
-set enable_material = off;
-set enable_mergejoin = off;
-set work_mem = '64kB';
-explain (costs off)
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-select final > 1 as multibatch
- from hash_join_batches(
-$$
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-$$);
-rollback to settings;
-
--- single-batch with rescan, parallel-oblivious
-savepoint settings;
-set enable_parallel_hash = off;
-set parallel_leader_participation = off;
-set min_parallel_table_scan_size = 0;
-set parallel_setup_cost = 0;
-set parallel_tuple_cost = 0;
-set max_parallel_workers_per_gather = 2;
-set enable_material = off;
-set enable_mergejoin = off;
-set work_mem = '4MB';
-explain (costs off)
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-select final > 1 as multibatch
- from hash_join_batches(
-$$
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-$$);
-rollback to settings;
-
--- multi-batch with rescan, parallel-aware
-savepoint settings;
-set enable_parallel_hash = on;
-set parallel_leader_participation = off;
-set min_parallel_table_scan_size = 0;
-set parallel_setup_cost = 0;
-set parallel_tuple_cost = 0;
-set max_parallel_workers_per_gather = 2;
-set enable_material = off;
-set enable_mergejoin = off;
-set work_mem = '64kB';
-explain (costs off)
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-select final > 1 as multibatch
- from hash_join_batches(
-$$
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-$$);
-rollback to settings;
-
--- single-batch with rescan, parallel-aware
-savepoint settings;
-set enable_parallel_hash = on;
-set parallel_leader_participation = off;
-set min_parallel_table_scan_size = 0;
-set parallel_setup_cost = 0;
-set parallel_tuple_cost = 0;
-set max_parallel_workers_per_gather = 2;
-set enable_material = off;
-set enable_mergejoin = off;
-set work_mem = '4MB';
-explain (costs off)
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-select final > 1 as multibatch
- from hash_join_batches(
-$$
- select count(*) from join_foo
- left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
- on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
-$$);
-rollback to settings;
-
--- A full outer join where every record is matched.
-
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-explain (costs off)
- select count(*) from simple r full outer join simple s using (id);
-select count(*) from simple r full outer join simple s using (id);
-rollback to settings;
-
--- parallelism not possible with parallel-oblivious outer hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-explain (costs off)
- select count(*) from simple r full outer join simple s using (id);
-select count(*) from simple r full outer join simple s using (id);
-rollback to settings;
-
--- An full outer join where every record is not matched.
-
--- non-parallel
-savepoint settings;
-set local max_parallel_workers_per_gather = 0;
-explain (costs off)
- select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
-select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
-rollback to settings;
-
--- parallelism not possible with parallel-oblivious outer hash join
-savepoint settings;
-set local max_parallel_workers_per_gather = 2;
-explain (costs off)
- select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
-select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
-rollback to settings;
-
--- exercise special code paths for huge tuples (note use of non-strict
--- expression and left join required to get the detoasted tuple into
--- the hash table)
-
--- parallel with parallel-aware hash join (hits ExecParallelHashLoadTuple and
--- sts_puttuple oversized tuple cases because it's multi-batch)
-savepoint settings;
-set max_parallel_workers_per_gather = 2;
-set enable_parallel_hash = on;
-set work_mem = '128kB';
-explain (costs off)
- select length(max(s.t))
- from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
-select length(max(s.t))
-from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
-select final > 1 as multibatch
- from hash_join_batches(
-$$
- select length(max(s.t))
- from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
-$$);
-rollback to settings;
-
-rollback;
diff --git a/src/test/regress/sql/join_hash.sql b/src/test/regress/sql/join_hash.sql
new file mode 100644
index 0000000..ae352e9
--- /dev/null
+++ b/src/test/regress/sql/join_hash.sql
@@ -0,0 +1,469 @@
+--
+-- exercises for the hash join code
+--
+
+begin;
+
+set local min_parallel_table_scan_size = 0;
+set local parallel_setup_cost = 0;
+
+-- Extract bucket and batch counts from an explain analyze plan. In
+-- general we can't make assertions about how many batches (or
+-- buckets) will be required because it can vary, but we can in some
+-- special cases and we can check for growth.
+create or replace function find_hash(node json)
+returns json language plpgsql
+as
+$$
+declare
+ x json;
+ child json;
+begin
+ if node->>'Node Type' = 'Hash' then
+ return node;
+ else
+ for child in select json_array_elements(node->'Plans')
+ loop
+ x := find_hash(child);
+ if x is not null then
+ return x;
+ end if;
+ end loop;
+ return null;
+ end if;
+end;
+$$;
+create or replace function hash_join_batches(query text)
+returns table (original int, final int) language plpgsql
+as
+$$
+declare
+ whole_plan json;
+ hash_node json;
+begin
+ for whole_plan in
+ execute 'explain (analyze, format ''json'') ' || query
+ loop
+ hash_node := find_hash(json_extract_path(whole_plan, '0', 'Plan'));
+ original := hash_node->>'Original Hash Batches';
+ final := hash_node->>'Hash Batches';
+ return next;
+ end loop;
+end;
+$$;
+
+-- Make a simple relation with well distributed keys and correctly
+-- estimated size.
+create table simple as
+ select generate_series(1, 20000) AS id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
+alter table simple set (parallel_workers = 2);
+analyze simple;
+
+-- Make a relation whose size we will under-estimate. We want stats
+-- to say 1000 rows, but actually there are 20,000 rows.
+create table bigger_than_it_looks as
+ select generate_series(1, 20000) as id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
+alter table bigger_than_it_looks set (autovacuum_enabled = 'false');
+alter table bigger_than_it_looks set (parallel_workers = 2);
+analyze bigger_than_it_looks;
+update pg_class set reltuples = 1000 where relname = 'bigger_than_it_looks';
+
+-- Make a relation whose size we underestimate and that also has a
+-- kind of skew that breaks our batching scheme. We want stats to say
+-- 2 rows, but actually there are 20,000 rows with the same key.
+create table extremely_skewed (id int, t text);
+alter table extremely_skewed set (autovacuum_enabled = 'false');
+alter table extremely_skewed set (parallel_workers = 2);
+analyze extremely_skewed;
+insert into extremely_skewed
+ select 42 as id, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+ from generate_series(1, 20000);
+update pg_class
+ set reltuples = 2, relpages = pg_relation_size('extremely_skewed') / 8192
+ where relname = 'extremely_skewed';
+
+-- Make a relation with a couple of enormous tuples.
+create table wide as select generate_series(1, 2) as id, rpad('', 320000, 'x') as t;
+alter table wide set (parallel_workers = 2);
+
+-- The "optimal" case: the hash table fits in memory; we plan for 1
+-- batch, we stick to that number, and peak memory usage stays within
+-- our work_mem budget
+
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+set local work_mem = '4MB';
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+select count(*) from simple r join simple s using (id);
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+rollback to settings;
+
+-- parallel with parallel-oblivious hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '4MB';
+set local enable_parallel_hash = off;
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+select count(*) from simple r join simple s using (id);
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+rollback to settings;
+
+-- parallel with parallel-aware hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '4MB';
+set local enable_parallel_hash = on;
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+select count(*) from simple r join simple s using (id);
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+rollback to settings;
+
+-- The "good" case: batches required, but we plan the right number; we
+-- plan for some number of batches, and we stick to that number, and
+-- peak memory usage says within our work_mem budget
+
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+set local work_mem = '128kB';
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+select count(*) from simple r join simple s using (id);
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+rollback to settings;
+
+-- parallel with parallel-oblivious hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '128kB';
+set local enable_parallel_hash = off;
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+select count(*) from simple r join simple s using (id);
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+rollback to settings;
+
+-- parallel with parallel-aware hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '192kB';
+set local enable_parallel_hash = on;
+explain (costs off)
+ select count(*) from simple r join simple s using (id);
+select count(*) from simple r join simple s using (id);
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+rollback to settings;
+
+-- The "bad" case: during execution we need to increase number of
+-- batches; in this case we plan for 1 batch, and increase at least a
+-- couple of times, and peak memory usage stays within our work_mem
+-- budget
+
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+set local work_mem = '128kB';
+explain (costs off)
+ select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
+select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) FROM simple r JOIN bigger_than_it_looks s USING (id);
+$$);
+rollback to settings;
+
+-- parallel with parallel-oblivious hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '128kB';
+set local enable_parallel_hash = off;
+explain (costs off)
+ select count(*) from simple r join bigger_than_it_looks s using (id);
+select count(*) from simple r join bigger_than_it_looks s using (id);
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join bigger_than_it_looks s using (id);
+$$);
+rollback to settings;
+
+-- parallel with parallel-aware hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 1;
+set local work_mem = '192kB';
+set local enable_parallel_hash = on;
+explain (costs off)
+ select count(*) from simple r join bigger_than_it_looks s using (id);
+select count(*) from simple r join bigger_than_it_looks s using (id);
+select original > 1 as initially_multibatch, final > original as increased_batches
+ from hash_join_batches(
+$$
+ select count(*) from simple r join bigger_than_it_looks s using (id);
+$$);
+rollback to settings;
+
+-- The "ugly" case: increasing the number of batches during execution
+-- doesn't help, so stop trying to fit in work_mem and hope for the
+-- best; in this case we plan for 1 batch, increases just once and
+-- then stop increasing because that didn't help at all, so we blow
+-- right through the work_mem budget and hope for the best...
+
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+set local work_mem = '128kB';
+explain (costs off)
+ select count(*) from simple r join extremely_skewed s using (id);
+select count(*) from simple r join extremely_skewed s using (id);
+select * from hash_join_batches(
+$$
+ select count(*) from simple r join extremely_skewed s using (id);
+$$);
+rollback to settings;
+
+-- parallel with parallel-oblivious hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '128kB';
+set local enable_parallel_hash = off;
+explain (costs off)
+ select count(*) from simple r join extremely_skewed s using (id);
+select count(*) from simple r join extremely_skewed s using (id);
+select * from hash_join_batches(
+$$
+ select count(*) from simple r join extremely_skewed s using (id);
+$$);
+rollback to settings;
+
+-- parallel with parallel-aware hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 1;
+set local work_mem = '128kB';
+set local enable_parallel_hash = on;
+explain (costs off)
+ select count(*) from simple r join extremely_skewed s using (id);
+select count(*) from simple r join extremely_skewed s using (id);
+select * from hash_join_batches(
+$$
+ select count(*) from simple r join extremely_skewed s using (id);
+$$);
+rollback to settings;
+
+-- A couple of other hash join tests unrelated to work_mem management.
+
+-- Check that EXPLAIN ANALYZE has data even if the leader doesn't participate
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+set local work_mem = '4MB';
+set local parallel_leader_participation = off;
+select * from hash_join_batches(
+$$
+ select count(*) from simple r join simple s using (id);
+$$);
+rollback to settings;
+
+-- Exercise rescans. We'll turn off parallel_leader_participation so
+-- that we can check that instrumentation comes back correctly.
+
+create table join_foo as select generate_series(1, 3) as id, 'xxxxx'::text as t;
+alter table join_foo set (parallel_workers = 0);
+create table join_bar as select generate_series(1, 10000) as id, 'xxxxx'::text as t;
+alter table join_bar set (parallel_workers = 2);
+
+-- multi-batch with rescan, parallel-oblivious
+savepoint settings;
+set enable_parallel_hash = off;
+set parallel_leader_participation = off;
+set min_parallel_table_scan_size = 0;
+set parallel_setup_cost = 0;
+set parallel_tuple_cost = 0;
+set max_parallel_workers_per_gather = 2;
+set enable_material = off;
+set enable_mergejoin = off;
+set work_mem = '64kB';
+explain (costs off)
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+select final > 1 as multibatch
+ from hash_join_batches(
+$$
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+$$);
+rollback to settings;
+
+-- single-batch with rescan, parallel-oblivious
+savepoint settings;
+set enable_parallel_hash = off;
+set parallel_leader_participation = off;
+set min_parallel_table_scan_size = 0;
+set parallel_setup_cost = 0;
+set parallel_tuple_cost = 0;
+set max_parallel_workers_per_gather = 2;
+set enable_material = off;
+set enable_mergejoin = off;
+set work_mem = '4MB';
+explain (costs off)
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+select final > 1 as multibatch
+ from hash_join_batches(
+$$
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+$$);
+rollback to settings;
+
+-- multi-batch with rescan, parallel-aware
+savepoint settings;
+set enable_parallel_hash = on;
+set parallel_leader_participation = off;
+set min_parallel_table_scan_size = 0;
+set parallel_setup_cost = 0;
+set parallel_tuple_cost = 0;
+set max_parallel_workers_per_gather = 2;
+set enable_material = off;
+set enable_mergejoin = off;
+set work_mem = '64kB';
+explain (costs off)
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+select final > 1 as multibatch
+ from hash_join_batches(
+$$
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+$$);
+rollback to settings;
+
+-- single-batch with rescan, parallel-aware
+savepoint settings;
+set enable_parallel_hash = on;
+set parallel_leader_participation = off;
+set min_parallel_table_scan_size = 0;
+set parallel_setup_cost = 0;
+set parallel_tuple_cost = 0;
+set max_parallel_workers_per_gather = 2;
+set enable_material = off;
+set enable_mergejoin = off;
+set work_mem = '4MB';
+explain (costs off)
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+select final > 1 as multibatch
+ from hash_join_batches(
+$$
+ select count(*) from join_foo
+ left join (select b1.id, b1.t from join_bar b1 join join_bar b2 using (id)) ss
+ on join_foo.id < ss.id + 1 and join_foo.id > ss.id - 1;
+$$);
+rollback to settings;
+
+-- A full outer join where every record is matched.
+
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+explain (costs off)
+ select count(*) from simple r full outer join simple s using (id);
+select count(*) from simple r full outer join simple s using (id);
+rollback to settings;
+
+-- parallelism not possible with parallel-oblivious outer hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+explain (costs off)
+ select count(*) from simple r full outer join simple s using (id);
+select count(*) from simple r full outer join simple s using (id);
+rollback to settings;
+
+-- An full outer join where every record is not matched.
+
+-- non-parallel
+savepoint settings;
+set local max_parallel_workers_per_gather = 0;
+explain (costs off)
+ select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
+select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
+rollback to settings;
+
+-- parallelism not possible with parallel-oblivious outer hash join
+savepoint settings;
+set local max_parallel_workers_per_gather = 2;
+explain (costs off)
+ select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
+select count(*) from simple r full outer join simple s on (r.id = 0 - s.id);
+rollback to settings;
+
+-- exercise special code paths for huge tuples (note use of non-strict
+-- expression and left join required to get the detoasted tuple into
+-- the hash table)
+
+-- parallel with parallel-aware hash join (hits ExecParallelHashLoadTuple and
+-- sts_puttuple oversized tuple cases because it's multi-batch)
+savepoint settings;
+set max_parallel_workers_per_gather = 2;
+set enable_parallel_hash = on;
+set work_mem = '128kB';
+explain (costs off)
+ select length(max(s.t))
+ from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
+select length(max(s.t))
+from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
+select final > 1 as multibatch
+ from hash_join_batches(
+$$
+ select length(max(s.t))
+ from wide left join (select id, coalesce(t, '') || '' as t from wide) s using (id);
+$$);
+rollback to settings;
+
+rollback;
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 9c8cf75..70deadf 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -1685,179 +1685,6 @@ SELECT * FROM perform_test;
drop table perform_test;
--
--- Test error trapping
---
-
-create function trap_zero_divide(int) returns int as $$
-declare x int;
- sx smallint;
-begin
- begin -- start a subtransaction
- raise notice 'should see this';
- x := 100 / $1;
- raise notice 'should see this only if % <> 0', $1;
- sx := $1;
- raise notice 'should see this only if % fits in smallint', $1;
- if $1 < 0 then
- raise exception '% is less than zero', $1;
- end if;
- exception
- when division_by_zero then
- raise notice 'caught division_by_zero';
- x := -1;
- when NUMERIC_VALUE_OUT_OF_RANGE then
- raise notice 'caught numeric_value_out_of_range';
- x := -2;
- end;
- return x;
-end$$ language plpgsql;
-
-select trap_zero_divide(50);
-select trap_zero_divide(0);
-select trap_zero_divide(100000);
-select trap_zero_divide(-100);
-
-create function trap_matching_test(int) returns int as $$
-declare x int;
- sx smallint;
- y int;
-begin
- begin -- start a subtransaction
- x := 100 / $1;
- sx := $1;
- select into y unique1 from tenk1 where unique2 =
- (select unique2 from tenk1 b where ten = $1);
- exception
- when data_exception then -- category match
- raise notice 'caught data_exception';
- x := -1;
- when NUMERIC_VALUE_OUT_OF_RANGE OR CARDINALITY_VIOLATION then
- raise notice 'caught numeric_value_out_of_range or cardinality_violation';
- x := -2;
- end;
- return x;
-end$$ language plpgsql;
-
-select trap_matching_test(50);
-select trap_matching_test(0);
-select trap_matching_test(100000);
-select trap_matching_test(1);
-
-create temp table foo (f1 int);
-
-create function subxact_rollback_semantics() returns int as $$
-declare x int;
-begin
- x := 1;
- insert into foo values(x);
- begin
- x := x + 1;
- insert into foo values(x);
- raise exception 'inner';
- exception
- when others then
- x := x * 10;
- end;
- insert into foo values(x);
- return x;
-end$$ language plpgsql;
-
-select subxact_rollback_semantics();
-select * from foo;
-drop table foo;
-
-create function trap_timeout() returns void as $$
-begin
- declare x int;
- begin
- -- we assume this will take longer than 2 seconds:
- select count(*) into x from tenk1 a, tenk1 b, tenk1 c;
- exception
- when others then
- raise notice 'caught others?';
- when query_canceled then
- raise notice 'nyeah nyeah, can''t stop me';
- end;
- -- Abort transaction to abandon the statement_timeout setting. Otherwise,
- -- the next top-level statement would be vulnerable to the timeout.
- raise exception 'end of function';
-end$$ language plpgsql;
-
-begin;
-set statement_timeout to 2000;
-select trap_timeout();
-rollback;
-
--- Test for pass-by-ref values being stored in proper context
-create function test_variable_storage() returns text as $$
-declare x text;
-begin
- x := '1234';
- begin
- x := x || '5678';
- -- force error inside subtransaction SPI context
- perform trap_zero_divide(-100);
- exception
- when others then
- x := x || '9012';
- end;
- return x;
-end$$ language plpgsql;
-
-select test_variable_storage();
-
---
--- test foreign key error trapping
---
-
-create temp table master(f1 int primary key);
-
-create temp table slave(f1 int references master deferrable);
-
-insert into master values(1);
-insert into slave values(1);
-insert into slave values(2); -- fails
-
-create function trap_foreign_key(int) returns int as $$
-begin
- begin -- start a subtransaction
- insert into slave values($1);
- exception
- when foreign_key_violation then
- raise notice 'caught foreign_key_violation';
- return 0;
- end;
- return 1;
-end$$ language plpgsql;
-
-create function trap_foreign_key_2() returns int as $$
-begin
- begin -- start a subtransaction
- set constraints all immediate;
- exception
- when foreign_key_violation then
- raise notice 'caught foreign_key_violation';
- return 0;
- end;
- return 1;
-end$$ language plpgsql;
-
-select trap_foreign_key(1);
-select trap_foreign_key(2); -- detects FK violation
-
-begin;
- set constraints all deferred;
- select trap_foreign_key(2); -- should not detect FK violation
- savepoint x;
- set constraints all immediate; -- fails
- rollback to x;
- select trap_foreign_key_2(); -- detects FK violation
-commit; -- still fails
-
-drop function trap_foreign_key(int);
-drop function trap_foreign_key_2();
-
---
-- Test proper snapshot handling in simple expressions
--
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index d3a6625..892ce4c 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -62,10 +62,6 @@ SET enable_seqscan = ON;
SET enable_indexscan = OFF;
SET enable_bitmapscan = OFF;
-CREATE TABLE quad_poly_tbl_ord_seq1 AS
-SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
-FROM quad_poly_tbl;
-
CREATE TABLE quad_poly_tbl_ord_seq2 AS
SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
@@ -129,21 +125,6 @@ SET enable_bitmapscan = OFF;
EXPLAIN (COSTS OFF)
SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
-FROM quad_poly_tbl;
-
-CREATE TEMP TABLE quad_poly_tbl_ord_idx1 AS
-SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
-FROM quad_poly_tbl;
-
-SELECT *
-FROM quad_poly_tbl_ord_seq1 seq FULL JOIN quad_poly_tbl_ord_idx1 idx
- ON seq.n = idx.n AND seq.id = idx.id AND
- (seq.dist = idx.dist OR seq.dist IS NULL AND idx.dist IS NULL)
-WHERE seq.id IS NULL OR idx.id IS NULL;
-
-
-EXPLAIN (COSTS OFF)
-SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
CREATE TEMP TABLE quad_poly_tbl_ord_idx2 AS
diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql
index 505dabd..a042e59 100644
--- a/src/test/regress/sql/rules.sql
+++ b/src/test/regress/sql/rules.sql
@@ -775,10 +775,13 @@ drop table cchild;
-- temporarily disable fancy output, so view changes create less diff noise
\a\t
-SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
+SELECT viewname, definition FROM pg_views
+WHERE schemaname IN ('pg_catalog', 'public')
+ORDER BY viewname;
SELECT tablename, rulename, definition FROM pg_rules
- ORDER BY tablename, rulename;
+WHERE schemaname IN ('pg_catalog', 'public')
+ORDER BY tablename, rulename;
-- restore normal output mode
\a\t