mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-04 00:02:52 -05:00 
			
		
		
		
	Add support for <-> (box, point) operator to GiST box_ops
Index-based calculation of this operator is exact. So, signature of gist_bbox_distance() function is changes so that caller is responsible for setting *recheck flag. Discussion: https://postgr.es/m/f71ba19d-d989-63b6-f04a-abf02ad9345d%40postgrespro.ru Author: Nikita Glukhov Reviewed-by: Tom Lane, Alexander Korotkov
This commit is contained in:
		
							parent
							
								
									6254c55f81
								
							
						
					
					
						commit
						c085e1c1cb
					
				@ -83,6 +83,7 @@
 | 
			
		||||
       <literal>~=</literal>
 | 
			
		||||
      </entry>
 | 
			
		||||
      <entry>
 | 
			
		||||
       <literal><-></literal>
 | 
			
		||||
      </entry>
 | 
			
		||||
     </row>
 | 
			
		||||
     <row>
 | 
			
		||||
 | 
			
		||||
@ -1464,26 +1464,12 @@ gist_point_distance(PG_FUNCTION_ARGS)
 | 
			
		||||
	PG_RETURN_FLOAT8(distance);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The inexact GiST distance method for geometric types that store bounding
 | 
			
		||||
 * boxes.
 | 
			
		||||
 *
 | 
			
		||||
 * Compute lossy distance from point to index entries.  The result is inexact
 | 
			
		||||
 * because index entries are bounding boxes, not the exact shapes of the
 | 
			
		||||
 * indexed geometric types.  We use distance from point to MBR of index entry.
 | 
			
		||||
 * This is a lower bound estimate of distance from point to indexed geometric
 | 
			
		||||
 * type.
 | 
			
		||||
 */
 | 
			
		||||
static float8
 | 
			
		||||
gist_bbox_distance(GISTENTRY *entry, Datum query,
 | 
			
		||||
				   StrategyNumber strategy, bool *recheck)
 | 
			
		||||
gist_bbox_distance(GISTENTRY *entry, Datum query, StrategyNumber strategy)
 | 
			
		||||
{
 | 
			
		||||
	float8		distance;
 | 
			
		||||
	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
 | 
			
		||||
 | 
			
		||||
	/* Bounding box distance is always inexact. */
 | 
			
		||||
	*recheck = true;
 | 
			
		||||
 | 
			
		||||
	switch (strategyGroup)
 | 
			
		||||
	{
 | 
			
		||||
		case PointStrategyNumberGroup:
 | 
			
		||||
@ -1499,6 +1485,32 @@ gist_bbox_distance(GISTENTRY *entry, Datum query,
 | 
			
		||||
	return distance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
gist_box_distance(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 | 
			
		||||
	Datum		query = PG_GETARG_DATUM(1);
 | 
			
		||||
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 | 
			
		||||
 | 
			
		||||
	/* Oid subtype = PG_GETARG_OID(3); */
 | 
			
		||||
	/* bool	   *recheck = (bool *) PG_GETARG_POINTER(4); */
 | 
			
		||||
	float8		distance;
 | 
			
		||||
 | 
			
		||||
	distance = gist_bbox_distance(entry, query, strategy);
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_FLOAT8(distance);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The inexact GiST distance methods for geometric types that store bounding
 | 
			
		||||
 * boxes.
 | 
			
		||||
 *
 | 
			
		||||
 * Compute lossy distance from point to index entries.  The result is inexact
 | 
			
		||||
 * because index entries are bounding boxes, not the exact shapes of the
 | 
			
		||||
 * indexed geometric types.  We use distance from point to MBR of index entry.
 | 
			
		||||
 * This is a lower bound estimate of distance from point to indexed geometric
 | 
			
		||||
 * type.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
gist_circle_distance(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
@ -1510,7 +1522,8 @@ gist_circle_distance(PG_FUNCTION_ARGS)
 | 
			
		||||
	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
 | 
			
		||||
	float8		distance;
 | 
			
		||||
 | 
			
		||||
	distance = gist_bbox_distance(entry, query, strategy, recheck);
 | 
			
		||||
	distance = gist_bbox_distance(entry, query, strategy);
 | 
			
		||||
	*recheck = true;
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_FLOAT8(distance);
 | 
			
		||||
}
 | 
			
		||||
@ -1526,7 +1539,8 @@ gist_poly_distance(PG_FUNCTION_ARGS)
 | 
			
		||||
	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
 | 
			
		||||
	float8		distance;
 | 
			
		||||
 | 
			
		||||
	distance = gist_bbox_distance(entry, query, strategy, recheck);
 | 
			
		||||
	distance = gist_bbox_distance(entry, query, strategy);
 | 
			
		||||
	*recheck = true;
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_FLOAT8(distance);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1081,6 +1081,9 @@
 | 
			
		||||
  amopstrategy => '13', amopopr => '~(box,box)', amopmethod => 'gist' },
 | 
			
		||||
{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box',
 | 
			
		||||
  amopstrategy => '14', amopopr => '@(box,box)', amopmethod => 'gist' },
 | 
			
		||||
{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'point',
 | 
			
		||||
  amopstrategy => '15', amoppurpose => 'o', amopopr => '<->(box,point)',
 | 
			
		||||
  amopmethod => 'gist', amopsortfamily => 'btree/float_ops' },
 | 
			
		||||
 | 
			
		||||
# gist point_ops
 | 
			
		||||
{ amopfamily => 'gist/point_ops', amoplefttype => 'point',
 | 
			
		||||
 | 
			
		||||
@ -419,6 +419,8 @@
 | 
			
		||||
  amprocrighttype => 'box', amprocnum => '6', amproc => 'gist_box_picksplit' },
 | 
			
		||||
{ amprocfamily => 'gist/box_ops', amproclefttype => 'box',
 | 
			
		||||
  amprocrighttype => 'box', amprocnum => '7', amproc => 'gist_box_same' },
 | 
			
		||||
{ amprocfamily => 'gist/box_ops', amproclefttype => 'box',
 | 
			
		||||
  amprocrighttype => 'box', amprocnum => '8', amproc => 'gist_box_distance' },
 | 
			
		||||
{ amprocfamily => 'gist/poly_ops', amproclefttype => 'polygon',
 | 
			
		||||
  amprocrighttype => 'polygon', amprocnum => '1',
 | 
			
		||||
  amproc => 'gist_poly_consistent' },
 | 
			
		||||
 | 
			
		||||
@ -7844,6 +7844,10 @@
 | 
			
		||||
{ oid => '2584', descr => 'GiST support',
 | 
			
		||||
  proname => 'gist_box_same', prorettype => 'internal',
 | 
			
		||||
  proargtypes => 'box box internal', prosrc => 'gist_box_same' },
 | 
			
		||||
{ oid => '3998', descr => 'GiST support',
 | 
			
		||||
  proname => 'gist_box_distance', prorettype => 'float8',
 | 
			
		||||
  proargtypes => 'internal box int2 oid internal',
 | 
			
		||||
  prosrc => 'gist_box_distance' },
 | 
			
		||||
{ oid => '2585', descr => 'GiST support',
 | 
			
		||||
  proname => 'gist_poly_consistent', prorettype => 'bool',
 | 
			
		||||
  proargtypes => 'internal polygon int2 oid internal',
 | 
			
		||||
 | 
			
		||||
@ -203,6 +203,82 @@ select b from gist_tbl where b <@ box(point(5,5), point(6,6));
 | 
			
		||||
 (6,6),(6,6)
 | 
			
		||||
(21 rows)
 | 
			
		||||
 | 
			
		||||
-- Also test an index-only knn-search
 | 
			
		||||
explain (costs off)
 | 
			
		||||
select b from gist_tbl where b <@ box(point(5,5), point(6,6))
 | 
			
		||||
order by b <-> point(5.2, 5.91);
 | 
			
		||||
                      QUERY PLAN                      
 | 
			
		||||
------------------------------------------------------
 | 
			
		||||
 Index Only Scan using gist_tbl_box_index on gist_tbl
 | 
			
		||||
   Index Cond: (b <@ '(6,6),(5,5)'::box)
 | 
			
		||||
   Order By: (b <-> '(5.2,5.91)'::point)
 | 
			
		||||
(3 rows)
 | 
			
		||||
 | 
			
		||||
select b from gist_tbl where b <@ box(point(5,5), point(6,6))
 | 
			
		||||
order by b <-> point(5.2, 5.91);
 | 
			
		||||
            b            
 | 
			
		||||
-------------------------
 | 
			
		||||
 (5.55,5.55),(5.55,5.55)
 | 
			
		||||
 (5.6,5.6),(5.6,5.6)
 | 
			
		||||
 (5.5,5.5),(5.5,5.5)
 | 
			
		||||
 (5.65,5.65),(5.65,5.65)
 | 
			
		||||
 (5.45,5.45),(5.45,5.45)
 | 
			
		||||
 (5.7,5.7),(5.7,5.7)
 | 
			
		||||
 (5.4,5.4),(5.4,5.4)
 | 
			
		||||
 (5.75,5.75),(5.75,5.75)
 | 
			
		||||
 (5.35,5.35),(5.35,5.35)
 | 
			
		||||
 (5.8,5.8),(5.8,5.8)
 | 
			
		||||
 (5.3,5.3),(5.3,5.3)
 | 
			
		||||
 (5.85,5.85),(5.85,5.85)
 | 
			
		||||
 (5.25,5.25),(5.25,5.25)
 | 
			
		||||
 (5.9,5.9),(5.9,5.9)
 | 
			
		||||
 (5.2,5.2),(5.2,5.2)
 | 
			
		||||
 (5.95,5.95),(5.95,5.95)
 | 
			
		||||
 (5.15,5.15),(5.15,5.15)
 | 
			
		||||
 (6,6),(6,6)
 | 
			
		||||
 (5.1,5.1),(5.1,5.1)
 | 
			
		||||
 (5.05,5.05),(5.05,5.05)
 | 
			
		||||
 (5,5),(5,5)
 | 
			
		||||
(21 rows)
 | 
			
		||||
 | 
			
		||||
-- Check commuted case as well
 | 
			
		||||
explain (costs off)
 | 
			
		||||
select b from gist_tbl where b <@ box(point(5,5), point(6,6))
 | 
			
		||||
order by point(5.2, 5.91) <-> b;
 | 
			
		||||
                      QUERY PLAN                      
 | 
			
		||||
------------------------------------------------------
 | 
			
		||||
 Index Only Scan using gist_tbl_box_index on gist_tbl
 | 
			
		||||
   Index Cond: (b <@ '(6,6),(5,5)'::box)
 | 
			
		||||
   Order By: (b <-> '(5.2,5.91)'::point)
 | 
			
		||||
(3 rows)
 | 
			
		||||
 | 
			
		||||
select b from gist_tbl where b <@ box(point(5,5), point(6,6))
 | 
			
		||||
order by point(5.2, 5.91) <-> b;
 | 
			
		||||
            b            
 | 
			
		||||
-------------------------
 | 
			
		||||
 (5.55,5.55),(5.55,5.55)
 | 
			
		||||
 (5.6,5.6),(5.6,5.6)
 | 
			
		||||
 (5.5,5.5),(5.5,5.5)
 | 
			
		||||
 (5.65,5.65),(5.65,5.65)
 | 
			
		||||
 (5.45,5.45),(5.45,5.45)
 | 
			
		||||
 (5.7,5.7),(5.7,5.7)
 | 
			
		||||
 (5.4,5.4),(5.4,5.4)
 | 
			
		||||
 (5.75,5.75),(5.75,5.75)
 | 
			
		||||
 (5.35,5.35),(5.35,5.35)
 | 
			
		||||
 (5.8,5.8),(5.8,5.8)
 | 
			
		||||
 (5.3,5.3),(5.3,5.3)
 | 
			
		||||
 (5.85,5.85),(5.85,5.85)
 | 
			
		||||
 (5.25,5.25),(5.25,5.25)
 | 
			
		||||
 (5.9,5.9),(5.9,5.9)
 | 
			
		||||
 (5.2,5.2),(5.2,5.2)
 | 
			
		||||
 (5.95,5.95),(5.95,5.95)
 | 
			
		||||
 (5.15,5.15),(5.15,5.15)
 | 
			
		||||
 (6,6),(6,6)
 | 
			
		||||
 (5.1,5.1),(5.1,5.1)
 | 
			
		||||
 (5.05,5.05),(5.05,5.05)
 | 
			
		||||
 (5,5),(5,5)
 | 
			
		||||
(21 rows)
 | 
			
		||||
 | 
			
		||||
drop index gist_tbl_box_index;
 | 
			
		||||
-- Test that an index-only scan is not chosen, when the query involves the
 | 
			
		||||
-- circle column (the circle opclass does not support index-only scans).
 | 
			
		||||
 | 
			
		||||
@ -109,6 +109,22 @@ select b from gist_tbl where b <@ box(point(5,5), point(6,6));
 | 
			
		||||
-- execute the same
 | 
			
		||||
select b from gist_tbl where b <@ box(point(5,5), point(6,6));
 | 
			
		||||
 | 
			
		||||
-- Also test an index-only knn-search
 | 
			
		||||
explain (costs off)
 | 
			
		||||
select b from gist_tbl where b <@ box(point(5,5), point(6,6))
 | 
			
		||||
order by b <-> point(5.2, 5.91);
 | 
			
		||||
 | 
			
		||||
select b from gist_tbl where b <@ box(point(5,5), point(6,6))
 | 
			
		||||
order by b <-> point(5.2, 5.91);
 | 
			
		||||
 | 
			
		||||
-- Check commuted case as well
 | 
			
		||||
explain (costs off)
 | 
			
		||||
select b from gist_tbl where b <@ box(point(5,5), point(6,6))
 | 
			
		||||
order by point(5.2, 5.91) <-> b;
 | 
			
		||||
 | 
			
		||||
select b from gist_tbl where b <@ box(point(5,5), point(6,6))
 | 
			
		||||
order by point(5.2, 5.91) <-> b;
 | 
			
		||||
 | 
			
		||||
drop index gist_tbl_box_index;
 | 
			
		||||
 | 
			
		||||
-- Test that an index-only scan is not chosen, when the query involves the
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user