]> granicus.if.org Git - postgresql/commitdiff
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;