Add polygon opclass for SP-GiST
authorTeodor Sigaev <teodor@sigaev.ru>
Mon, 25 Dec 2017 15:59:38 +0000 (18:59 +0300)
committerTeodor Sigaev <teodor@sigaev.ru>
Mon, 25 Dec 2017 15:59:38 +0000 (18:59 +0300)
Polygon opclass uses compress method feature of SP-GiST added earlier. For now
it's a single operator class which uses this feature. SP-GiST actually indexes
a bounding boxes of input polygons, so part of supported operations are lossy.
Opclass uses most methods of corresponding opclass over boxes of SP-GiST and
treats bounding boxes as point in 4D-space.

Bump catalog version.

Authors: Nikita Glukhov, Alexander Korotkov with minor editorization by me
Reviewed-By: all authors + Darafei Praliaskouski
Discussion: https://www.postgresql.org/message-id/flat/54907069.1030506@sigaev.ru

13 files changed:
doc/src/sgml/spgist.sgml
src/backend/utils/adt/geo_ops.c
src/backend/utils/adt/geo_spgist.c
src/include/catalog/catversion.h
src/include/catalog/pg_amop.h
src/include/catalog/pg_amproc.h
src/include/catalog/pg_opclass.h
src/include/catalog/pg_opfamily.h
src/include/catalog/pg_proc.h
src/include/utils/geo_decls.h
src/test/regress/expected/polygon.out
src/test/regress/expected/sanity_check.out
src/test/regress/sql/polygon.sql

index b4a8be476e79de544759e00f7ba6cf5d4a50747c..51bb60c92a016b5ea317803f736b0a4b6569b22d 100644 (file)
        <literal>|&amp;&gt;</literal>
       </entry>
      </row>
+     <row>
+      <entry><literal>poly_ops</literal></entry>
+      <entry><type>polygon</type></entry>
+      <entry>
+       <literal>&lt;&lt;</literal>
+       <literal>&amp;&lt;</literal>
+       <literal>&amp;&amp;</literal>
+       <literal>&amp;&gt;</literal>
+       <literal>&gt;&gt;</literal>
+       <literal>~=</literal>
+       <literal>@&gt;</literal>
+       <literal>&lt;@</literal>
+       <literal>&amp;&lt;|</literal>
+       <literal>&lt;&lt;|</literal>
+       <literal>|&gt;&gt;</literal>
+       <literal>|&amp;&gt;</literal>
+      </entry>
+     </row>
+     <row>
+      <entry><literal>poly_ops</literal></entry>
+      <entry><type>polygon</type></entry>
+      <entry>
+       <literal>&lt;&lt;</literal>
+       <literal>&amp;&lt;</literal>
+       <literal>&amp;&amp;</literal>
+       <literal>&amp;&gt;</literal>
+       <literal>&gt;&gt;</literal>
+       <literal>~=</literal>
+       <literal>@&gt;</literal>
+       <literal>&lt;@</literal>
+       <literal>&amp;&lt;|</literal>
+       <literal>&lt;&lt;|</literal>
+       <literal>|&gt;&gt;</literal>
+       <literal>|&amp;&gt;</literal>
+      </entry>
+     </row>
      <row>
       <entry><literal>text_ops</literal></entry>
       <entry><type>text</type></entry>
index 9dbe5db2b2be12bf40466d24c191fff56729ff16..f00ea5403372df8b224932d855ae65d5605d4831 100644 (file)
@@ -41,7 +41,6 @@ enum path_delim
 static int point_inside(Point *p, int npts, Point *plist);
 static int lseg_crossing(double x, double y, double px, double py);
 static BOX *box_construct(double x1, double x2, double y1, double y2);
-static BOX *box_copy(BOX *box);
 static BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2);
 static bool box_ov(BOX *box1, BOX *box2);
 static double box_ht(BOX *box);
@@ -482,7 +481,7 @@ box_fill(BOX *result, double x1, double x2, double y1, double y2)
 
 /*     box_copy        -       copy a box
  */
-static BOX *
+BOX *
 box_copy(BOX *box)
 {
    BOX        *result = (BOX *) palloc(sizeof(BOX));
index f6334bae14edda87d688b11c73e1a4366020a258..a10543600fec829b760437aa3e53fcca003031dc 100644 (file)
@@ -391,7 +391,7 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
    spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
    spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
    BOX        *centroid = DatumGetBoxP(in->prefixDatum),
-              *box = DatumGetBoxP(in->datum);
+              *box = DatumGetBoxP(in->leafDatum);
 
    out->resultType = spgMatchNode;
    out->result.matchNode.restDatum = BoxPGetDatum(box);
@@ -473,6 +473,51 @@ spg_box_quad_picksplit(PG_FUNCTION_ARGS)
    PG_RETURN_VOID();
 }
 
+/*
+ * Check if result of consistent method based on bounding box is exact.
+ */
+static bool
+is_bounding_box_test_exact(StrategyNumber strategy)
+{
+   switch (strategy)
+   {
+       case RTLeftStrategyNumber:
+       case RTOverLeftStrategyNumber:
+       case RTOverRightStrategyNumber:
+       case RTRightStrategyNumber:
+       case RTOverBelowStrategyNumber:
+       case RTBelowStrategyNumber:
+       case RTAboveStrategyNumber:
+       case RTOverAboveStrategyNumber:
+           return true;
+
+       default:
+           return false;
+   }
+}
+
+/*
+ * Get bounding box for ScanKey.
+ */
+static BOX *
+spg_box_quad_get_scankey_bbox(ScanKey sk, bool *recheck)
+{
+   switch (sk->sk_subtype)
+   {
+       case BOXOID:
+           return DatumGetBoxP(sk->sk_argument);
+
+       case POLYGONOID:
+           if (recheck && !is_bounding_box_test_exact(sk->sk_strategy))
+               *recheck = true;
+           return &DatumGetPolygonP(sk->sk_argument)->boundbox;
+
+       default:
+           elog(ERROR, "unrecognized scankey subtype: %d", sk->sk_subtype);
+           return NULL;
+   }
+}
+
 /*
  * SP-GiST inner consistent function
  */
@@ -515,7 +560,11 @@ spg_box_quad_inner_consistent(PG_FUNCTION_ARGS)
    centroid = getRangeBox(DatumGetBoxP(in->prefixDatum));
    queries = (RangeBox **) palloc(in->nkeys * sizeof(RangeBox *));
    for (i = 0; i < in->nkeys; i++)
-       queries[i] = getRangeBox(DatumGetBoxP(in->scankeys[i].sk_argument));
+   {
+       BOX        *box = spg_box_quad_get_scankey_bbox(&in->scankeys[i], NULL);
+
+       queries[i] = getRangeBox(box);
+   }
 
    /* Allocate enough memory for nodes */
    out->nNodes = 0;
@@ -637,8 +686,10 @@ spg_box_quad_leaf_consistent(PG_FUNCTION_ARGS)
    /* Perform the required comparison(s) */
    for (i = 0; i < in->nkeys; i++)
    {
-       StrategyNumber strategy = in->scankeys[i].sk_strategy;
-       Datum       query = in->scankeys[i].sk_argument;
+       StrategyNumber  strategy = in->scankeys[i].sk_strategy;
+       BOX            *box = spg_box_quad_get_scankey_bbox(&in->scankeys[i],
+                                                           &out->recheck);
+       Datum           query = BoxPGetDatum(box);
 
        switch (strategy)
        {
@@ -713,3 +764,36 @@ spg_box_quad_leaf_consistent(PG_FUNCTION_ARGS)
 
    PG_RETURN_BOOL(flag);
 }
+
+
+/*
+ * SP-GiST config function for 2-D types that are lossy represented by their
+ * bounding boxes
+ */
+Datum
+spg_bbox_quad_config(PG_FUNCTION_ARGS)
+{
+   spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1);
+
+   cfg->prefixType = BOXOID;   /* A type represented by its bounding box */
+   cfg->labelType = VOIDOID;   /* We don't need node labels. */
+   cfg->leafType = BOXOID;
+   cfg->canReturnData = false;
+   cfg->longValuesOK = false;
+
+   PG_RETURN_VOID();
+}
+
+/*
+ * SP-GiST compress function for polygons
+ */
+Datum
+spg_poly_quad_compress(PG_FUNCTION_ARGS)
+{
+   POLYGON    *polygon = PG_GETARG_POLYGON_P(0);
+   BOX        *box;
+
+   box = box_copy(&polygon->boundbox);
+
+   PG_RETURN_BOX_P(box);
+}
index b13cf62beca9006678dc93a3789587b6bba0e8d3..3934582efce04511b747c94d12760c82de0480b2 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201711301
+#define CATALOG_VERSION_NO 201712251
 
 #endif
index f850be490af3ebf6c7762b95a465dff8f6b8e134..d8770798a697b91195d8c40cc4dd7487a338b8a9 100644 (file)
@@ -857,6 +857,22 @@ DATA(insert (  5000    603  603 10 s   2570    4000 0 ));
 DATA(insert (  5000    603  603 11 s   2573    4000 0 ));
 DATA(insert (  5000    603  603 12 s   2572    4000 0 ));
 
+/*
+ * SP-GiST poly_ops (supports polygons)
+ */
+DATA(insert (  5008   604  604  1 s     485    4000 0 ));
+DATA(insert (  5008   604  604  2 s     486    4000 0 ));
+DATA(insert (  5008   604  604  3 s     492    4000 0 ));
+DATA(insert (  5008   604  604  4 s     487    4000 0 ));
+DATA(insert (  5008   604  604  5 s     488    4000 0 ));
+DATA(insert (  5008   604  604  6 s     491    4000 0 ));
+DATA(insert (  5008   604  604  7 s     490    4000 0 ));
+DATA(insert (  5008   604  604  8 s     489    4000 0 ));
+DATA(insert (  5008   604  604  9 s    2575    4000 0 ));
+DATA(insert (  5008   604  604 10 s    2574    4000 0 ));
+DATA(insert (  5008   604  604 11 s    2577    4000 0 ));
+DATA(insert (  5008   604  604 12 s    2576    4000 0 ));
+
 /*
  * GiST inet_ops
  */
index 1c958462074b8e2746a53a4c736b1f206f61a45f..b25ad105fd1faee8e54c270178d8c1d09d3f0936 100644 (file)
@@ -334,6 +334,12 @@ DATA(insert (  5000   603 603 2 5013 ));
 DATA(insert (  5000   603 603 3 5014 ));
 DATA(insert (  5000   603 603 4 5015 ));
 DATA(insert (  5000   603 603 5 5016 ));
+DATA(insert (  5008   604 604 1 5010 ));
+DATA(insert (  5008   604 604 2 5013 ));
+DATA(insert (  5008   604 604 3 5014 ));
+DATA(insert (  5008   604 604 4 5015 ));
+DATA(insert (  5008   604 604 5 5016 ));
+DATA(insert (  5008   604 604 6 5011 ));
 
 /* BRIN opclasses */
 /* minmax bytea */
index 28dbc747d5b7a3e59a41a845ddd1edb8d44b40eb..6aabc7279fe9c166b4c1ad78dc580218061af65a 100644 (file)
@@ -205,6 +205,7 @@ DATA(insert (   4000    box_ops             PGNSP PGUID 5000  603  t 0 ));
 DATA(insert (  4000    quad_point_ops      PGNSP PGUID 4015  600 t 0 ));
 DATA(insert (  4000    kd_point_ops        PGNSP PGUID 4016  600 f 0 ));
 DATA(insert (  4000    text_ops            PGNSP PGUID 4017  25 t 0 ));
+DATA(insert (  4000    poly_ops            PGNSP PGUID 5008  604 t 603 ));
 DATA(insert (  403     jsonb_ops           PGNSP PGUID 4033  3802 t 0 ));
 DATA(insert (  405     jsonb_ops           PGNSP PGUID 4034  3802 t 0 ));
 DATA(insert (  2742    jsonb_ops           PGNSP PGUID 4036  3802 t 25 ));
index 0d0ba7c66a205e0efcc9f1e4a8af1252e5993ac2..838812b9328409f2adf4edf892feea964ef38794 100644 (file)
@@ -186,5 +186,6 @@ DATA(insert OID = 4103 (    3580    range_inclusion_ops     PGNSP PGUID ));
 DATA(insert OID = 4082 (   3580    pg_lsn_minmax_ops       PGNSP PGUID ));
 DATA(insert OID = 4104 (   3580    box_inclusion_ops       PGNSP PGUID ));
 DATA(insert OID = 5000 (   4000    box_ops     PGNSP PGUID ));
+DATA(insert OID = 5008 (   4000    poly_ops                PGNSP PGUID ));
 
 #endif                         /* PG_OPFAMILY_H */
index c9693759811f70a051ce28d0d2a513dfdccba087..830bab37eae04720910d9d1796d16d5dbfebca0f 100644 (file)
@@ -5335,6 +5335,11 @@ DESCR("SP-GiST support for quad tree over box");
 DATA(insert OID = 5016 (  spg_box_quad_leaf_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_  _null_ spg_box_quad_leaf_consistent _null_ _null_ _null_ ));
 DESCR("SP-GiST support for quad tree over box");
 
+DATA(insert OID = 5010 (  spg_bbox_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_  _null_ spg_bbox_quad_config _null_ _null_ _null_ ));
+DESCR("SP-GiST support for quad tree over 2-D types represented by their bounding boxes");
+DATA(insert OID = 5011 (  spg_poly_quad_compress PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 603 "604" _null_ _null_ _null_ _null_  _null_ spg_poly_quad_compress _null_ _null_ _null_ ));
+DESCR("SP-GiST support for quad tree over polygons");
+
 /* replication slots */
 DATA(insert OID = 3779 (  pg_create_physical_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 2249 "19 16 16" "{19,16,16,19,3220}" "{i,i,i,o,o}" "{slot_name,immediately_reserve,temporary,slot_name,lsn}" _null_ _null_ pg_create_physical_replication_slot _null_ _null_ _null_ ));
 DESCR("create a physical replication slot");
index 44c6381b855596bf502b0e6313853ad63013f5b7..c89e6c3d1cf5e0807b78695fbb92edca22c4fcda 100644 (file)
@@ -178,9 +178,10 @@ typedef struct
  * in geo_ops.c
  */
 
-/* private point routines */
+/* private routines */
 extern double point_dt(Point *pt1, Point *pt2);
 extern double point_sl(Point *pt1, Point *pt2);
 extern double pg_hypot(double x, double y);
+extern BOX *box_copy(BOX *box);
 
 #endif                         /* GEO_DECLS_H */
index 2361274f9e83b95b8dd0a39c9ea41c96e80f3833..4a1f60427ab748bb9793abcc8982d6baae4a2c1a 100644 (file)
@@ -227,3 +227,241 @@ SELECT    '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
          0 |          0 |      0 | 1.4142135623731 |          3.2
 (1 row)
 
+--
+-- Test the SP-GiST index
+--
+CREATE TABLE quad_poly_tbl (id int, p polygon);
+INSERT INTO quad_poly_tbl
+   SELECT (x - 1) * 100 + y, polygon(circle(point(x * 10, y * 10), 1 + (x + y) % 10))
+   FROM generate_series(1, 100) x,
+        generate_series(1, 100) y;
+INSERT INTO quad_poly_tbl
+   SELECT i, polygon '((200, 300),(210, 310),(230, 290))'
+   FROM generate_series(10001, 11000) AS i;
+INSERT INTO quad_poly_tbl
+   VALUES
+       (11001, NULL),
+       (11002, NULL),
+       (11003, NULL);
+CREATE INDEX quad_poly_tbl_idx ON quad_poly_tbl USING spgist(p);
+-- get reference results for ORDER BY distance from seq scan
+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))';
+-- check results results from index scan
+SET enable_seqscan = OFF;
+SET enable_indexscan = OFF;
+SET enable_bitmapscan = ON;
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p << polygon '((300,300),(400,600),(600,500),(700,200))';
+                                      QUERY PLAN                                       
+---------------------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p << '((300,300),(400,600),(600,500),(700,200))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p << '((300,300),(400,600),(600,500),(700,200))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p << polygon '((300,300),(400,600),(600,500),(700,200))';
+ count 
+-------
+  3890
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p &< polygon '((300,300),(400,600),(600,500),(700,200))';
+                                      QUERY PLAN                                       
+---------------------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p &< '((300,300),(400,600),(600,500),(700,200))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p &< '((300,300),(400,600),(600,500),(700,200))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p &< polygon '((300,300),(400,600),(600,500),(700,200))';
+ count 
+-------
+  7900
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p && polygon '((300,300),(400,600),(600,500),(700,200))';
+                                      QUERY PLAN                                       
+---------------------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p && '((300,300),(400,600),(600,500),(700,200))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p && '((300,300),(400,600),(600,500),(700,200))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p && polygon '((300,300),(400,600),(600,500),(700,200))';
+ count 
+-------
+   977
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p &> polygon '((300,300),(400,600),(600,500),(700,200))';
+                                      QUERY PLAN                                       
+---------------------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p &> '((300,300),(400,600),(600,500),(700,200))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p &> '((300,300),(400,600),(600,500),(700,200))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p &> polygon '((300,300),(400,600),(600,500),(700,200))';
+ count 
+-------
+  7000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p >> polygon '((300,300),(400,600),(600,500),(700,200))';
+                                      QUERY PLAN                                       
+---------------------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p >> '((300,300),(400,600),(600,500),(700,200))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p >> '((300,300),(400,600),(600,500),(700,200))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p >> polygon '((300,300),(400,600),(600,500),(700,200))';
+ count 
+-------
+  2990
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p <<| polygon '((300,300),(400,600),(600,500),(700,200))';
+                                       QUERY PLAN                                       
+----------------------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p <<| '((300,300),(400,600),(600,500),(700,200))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p <<| '((300,300),(400,600),(600,500),(700,200))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p <<| polygon '((300,300),(400,600),(600,500),(700,200))';
+ count 
+-------
+  1890
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p &<| polygon '((300,300),(400,600),(600,500),(700,200))';
+                                       QUERY PLAN                                       
+----------------------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p &<| '((300,300),(400,600),(600,500),(700,200))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p &<| '((300,300),(400,600),(600,500),(700,200))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p &<| polygon '((300,300),(400,600),(600,500),(700,200))';
+ count 
+-------
+  6900
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p |&> polygon '((300,300),(400,600),(600,500),(700,200))';
+                                       QUERY PLAN                                       
+----------------------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p |&> '((300,300),(400,600),(600,500),(700,200))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p |&> '((300,300),(400,600),(600,500),(700,200))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p |&> polygon '((300,300),(400,600),(600,500),(700,200))';
+ count 
+-------
+  9000
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p |>> polygon '((300,300),(400,600),(600,500),(700,200))';
+                                       QUERY PLAN                                       
+----------------------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p |>> '((300,300),(400,600),(600,500),(700,200))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p |>> '((300,300),(400,600),(600,500),(700,200))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p |>> polygon '((300,300),(400,600),(600,500),(700,200))';
+ count 
+-------
+  3990
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
+                                      QUERY PLAN                                       
+---------------------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p <@ '((300,300),(400,600),(600,500),(700,200))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p <@ '((300,300),(400,600),(600,500),(700,200))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
+ count 
+-------
+   831
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p @> polygon '((340,550),(343,552),(341,553))';
+                                 QUERY PLAN                                  
+-----------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p @> '((340,550),(343,552),(341,553))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p @> '((340,550),(343,552),(341,553))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p @> polygon '((340,550),(343,552),(341,553))';
+ count 
+-------
+     1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p ~= polygon '((200, 300),(210, 310),(230, 290))';
+                                 QUERY PLAN                                  
+-----------------------------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on quad_poly_tbl
+         Recheck Cond: (p ~= '((200,300),(210,310),(230,290))'::polygon)
+         ->  Bitmap Index Scan on quad_poly_tbl_idx
+               Index Cond: (p ~= '((200,300),(210,310),(230,290))'::polygon)
+(5 rows)
+
+SELECT count(*) FROM quad_poly_tbl WHERE p ~= polygon '((200, 300),(210, 310),(230, 290))';
+ count 
+-------
+  1000
+(1 row)
+
+RESET enable_seqscan;
+RESET enable_indexscan;
+RESET enable_bitmapscan;
index e9966405933fa1d372572ee9ffb0ee919cc337f1..ac0fb539e98ff0f16c5a0d11bd66761e69230cd4 100644 (file)
@@ -166,6 +166,9 @@ point_tbl|t
 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
 real_city|f
index 7ac807946566f274d0d81fd8f9fd49dc5c216c93..7e8cb08cd8b3ae36bb6085e18b592c2e7fde9812 100644 (file)
@@ -116,3 +116,96 @@ SELECT '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
    '(2,2)'::point <-> '((0,0),(1,4),(3,1))'::polygon as inside,
    '(3,3)'::point <-> '((0,2),(2,0),(2,2))'::polygon as near_corner,
    '(4,4)'::point <-> '((0,0),(0,3),(4,0))'::polygon as near_segment;
+
+--
+-- Test the SP-GiST index
+--
+
+CREATE TABLE quad_poly_tbl (id int, p polygon);
+
+INSERT INTO quad_poly_tbl
+   SELECT (x - 1) * 100 + y, polygon(circle(point(x * 10, y * 10), 1 + (x + y) % 10))
+   FROM generate_series(1, 100) x,
+        generate_series(1, 100) y;
+
+INSERT INTO quad_poly_tbl
+   SELECT i, polygon '((200, 300),(210, 310),(230, 290))'
+   FROM generate_series(10001, 11000) AS i;
+
+INSERT INTO quad_poly_tbl
+   VALUES
+       (11001, NULL),
+       (11002, NULL),
+       (11003, NULL);
+
+CREATE INDEX quad_poly_tbl_idx ON quad_poly_tbl USING spgist(p);
+
+-- get reference results for ORDER BY distance from seq scan
+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))';
+
+-- check results results from index scan
+SET enable_seqscan = OFF;
+SET enable_indexscan = OFF;
+SET enable_bitmapscan = ON;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p << polygon '((300,300),(400,600),(600,500),(700,200))';
+SELECT count(*) FROM quad_poly_tbl WHERE p << polygon '((300,300),(400,600),(600,500),(700,200))';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p &< polygon '((300,300),(400,600),(600,500),(700,200))';
+SELECT count(*) FROM quad_poly_tbl WHERE p &< polygon '((300,300),(400,600),(600,500),(700,200))';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p && polygon '((300,300),(400,600),(600,500),(700,200))';
+SELECT count(*) FROM quad_poly_tbl WHERE p && polygon '((300,300),(400,600),(600,500),(700,200))';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p &> polygon '((300,300),(400,600),(600,500),(700,200))';
+SELECT count(*) FROM quad_poly_tbl WHERE p &> polygon '((300,300),(400,600),(600,500),(700,200))';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p >> polygon '((300,300),(400,600),(600,500),(700,200))';
+SELECT count(*) FROM quad_poly_tbl WHERE p >> polygon '((300,300),(400,600),(600,500),(700,200))';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p <<| polygon '((300,300),(400,600),(600,500),(700,200))';
+SELECT count(*) FROM quad_poly_tbl WHERE p <<| polygon '((300,300),(400,600),(600,500),(700,200))';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p &<| polygon '((300,300),(400,600),(600,500),(700,200))';
+SELECT count(*) FROM quad_poly_tbl WHERE p &<| polygon '((300,300),(400,600),(600,500),(700,200))';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p |&> polygon '((300,300),(400,600),(600,500),(700,200))';
+SELECT count(*) FROM quad_poly_tbl WHERE p |&> polygon '((300,300),(400,600),(600,500),(700,200))';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p |>> polygon '((300,300),(400,600),(600,500),(700,200))';
+SELECT count(*) FROM quad_poly_tbl WHERE p |>> polygon '((300,300),(400,600),(600,500),(700,200))';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
+SELECT count(*) FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p @> polygon '((340,550),(343,552),(341,553))';
+SELECT count(*) FROM quad_poly_tbl WHERE p @> polygon '((340,550),(343,552),(341,553))';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM quad_poly_tbl WHERE p ~= polygon '((200, 300),(210, 310),(230, 290))';
+SELECT count(*) FROM quad_poly_tbl WHERE p ~= polygon '((200, 300),(210, 310),(230, 290))';
+
+RESET enable_seqscan;
+RESET enable_indexscan;
+RESET enable_bitmapscan;