diff --git a/doc/src/sgml/spgist.sgml b/doc/src/sgml/spgist.sgml
new file mode 100644
index dcdc297..bac9979
*** a/doc/src/sgml/spgist.sgml
--- b/doc/src/sgml/spgist.sgml
***************
*** 131,136 ****
--- 131,172 ----
        </entry>
       </row>
       <row>
+       <entry><literal>circle_ops</></entry>
+       <entry><type>circle</></entry>
+       <entry>
+        <literal>&lt;&lt;</>
+        <literal>&amp;&lt;</>
+        <literal>&amp;&amp;</>
+        <literal>&amp;&gt;</>
+        <literal>&gt;&gt;</>
+        <literal>~=</>
+        <literal>@&gt;</>
+        <literal>&lt;@</>
+        <literal>&amp;&lt;|</>
+        <literal>&lt;&lt;|</>
+        <literal>|&gt;&gt;</>
+        <literal>|&amp;&gt;</>
+       </entry>
+      </row>
+      <row>
+       <entry><literal>poly_ops</></entry>
+       <entry><type>polygon</></entry>
+       <entry>
+        <literal>&lt;&lt;</>
+        <literal>&amp;&lt;</>
+        <literal>&amp;&amp;</>
+        <literal>&amp;&gt;</>
+        <literal>&gt;&gt;</>
+        <literal>~=</>
+        <literal>@&gt;</>
+        <literal>&lt;@</>
+        <literal>&amp;&lt;|</>
+        <literal>&lt;&lt;|</>
+        <literal>|&gt;&gt;</>
+        <literal>|&amp;&gt;</>
+       </entry>
+      </row>
+      <row>
        <entry><literal>text_ops</></entry>
        <entry><type>text</></entry>
        <entry>
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
new file mode 100644
index 0348855..4b93b88
*** a/src/backend/utils/adt/geo_ops.c
--- b/src/backend/utils/adt/geo_ops.c
*************** enum path_delim
*** 41,47 ****
  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);
--- 41,46 ----
*************** box_fill(BOX *result, double x1, double 
*** 482,488 ****
  
  /*		box_copy		-		copy a box
   */
! static BOX *
  box_copy(BOX *box)
  {
  	BOX		   *result = (BOX *) palloc(sizeof(BOX));
--- 481,487 ----
  
  /*		box_copy		-		copy a box
   */
! BOX *
  box_copy(BOX *box)
  {
  	BOX		   *result = (BOX *) palloc(sizeof(BOX));
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
new file mode 100644
index f6334ba..a105436
*** a/src/backend/utils/adt/geo_spgist.c
--- b/src/backend/utils/adt/geo_spgist.c
*************** spg_box_quad_choose(PG_FUNCTION_ARGS)
*** 391,397 ****
  	spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
  	spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
  	BOX		   *centroid = DatumGetBoxP(in->prefixDatum),
! 			   *box = DatumGetBoxP(in->datum);
  
  	out->resultType = spgMatchNode;
  	out->result.matchNode.restDatum = BoxPGetDatum(box);
--- 391,397 ----
  	spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
  	spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
  	BOX		   *centroid = DatumGetBoxP(in->prefixDatum),
! 			   *box = DatumGetBoxP(in->leafDatum);
  
  	out->resultType = spgMatchNode;
  	out->result.matchNode.restDatum = BoxPGetDatum(box);
*************** spg_box_quad_picksplit(PG_FUNCTION_ARGS)
*** 474,479 ****
--- 474,524 ----
  }
  
  /*
+  * 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
   */
  Datum
*************** spg_box_quad_inner_consistent(PG_FUNCTIO
*** 515,521 ****
  	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));
  
  	/* Allocate enough memory for nodes */
  	out->nNodes = 0;
--- 560,570 ----
  	centroid = getRangeBox(DatumGetBoxP(in->prefixDatum));
  	queries = (RangeBox **) palloc(in->nkeys * sizeof(RangeBox *));
  	for (i = 0; i < in->nkeys; i++)
! 	{
! 		BOX		   *box = spg_box_quad_get_scankey_bbox(&in->scankeys[i], NULL);
! 
! 		queries[i] = getRangeBox(box);
! 	}
  
  	/* Allocate enough memory for nodes */
  	out->nNodes = 0;
*************** spg_box_quad_leaf_consistent(PG_FUNCTION
*** 637,644 ****
  	/* 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;
  
  		switch (strategy)
  		{
--- 686,695 ----
  	/* Perform the required comparison(s) */
  	for (i = 0; i < in->nkeys; i++)
  	{
! 		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)
  		{
*************** spg_box_quad_leaf_consistent(PG_FUNCTION
*** 713,715 ****
--- 764,799 ----
  
  	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);
+ }
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
new file mode 100644
index f850be4..d877079
*** a/src/include/catalog/pg_amop.h
--- b/src/include/catalog/pg_amop.h
*************** DATA(insert (	5000	603  603 11 s	2573	40
*** 858,863 ****
--- 858,879 ----
  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
   */
  DATA(insert (	3550	869 869 3 s		3552 783 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
new file mode 100644
index 1c95846..8b0c26b
*** a/src/include/catalog/pg_amproc.h
--- b/src/include/catalog/pg_amproc.h
*************** DATA(insert (	5000   603 603 2 5013 ));
*** 334,339 ****
--- 334,345 ----
  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 5009 ));
+ 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 */
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
new file mode 100644
index 28dbc74..6aabc72
*** a/src/include/catalog/pg_opclass.h
--- b/src/include/catalog/pg_opclass.h
*************** DATA(insert (	4000	box_ops				PGNSP PGUI
*** 205,210 ****
--- 205,211 ----
  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 ));
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
new file mode 100644
index 0d0ba7c..838812b
*** a/src/include/catalog/pg_opfamily.h
--- b/src/include/catalog/pg_opfamily.h
*************** DATA(insert OID = 4103 (	3580	range_incl
*** 186,190 ****
--- 186,191 ----
  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 */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index 93c031a..376f33a
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("SP-GiST support for quad tree ove
*** 5335,5340 ****
--- 5335,5345 ----
  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 = 5009 (  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");
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
new file mode 100644
index 44c6381..c89e6c3
*** a/src/include/utils/geo_decls.h
--- b/src/include/utils/geo_decls.h
*************** typedef struct
*** 178,186 ****
   * in geo_ops.c
   */
  
! /* private point 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);
  
  #endif							/* GEO_DECLS_H */
--- 178,187 ----
   * in geo_ops.c
   */
  
! /* 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 */
diff --git a/src/test/regress/expected/polygon.out b/src/test/regress/expected/polygon.out
new file mode 100644
index 2361274..a9e7752
*** a/src/test/regress/expected/polygon.out
--- b/src/test/regress/expected/polygon.out
*************** SELECT	'(0,0)'::point <-> '((0,0),(1,2),
*** 227,229 ****
--- 227,467 ----
           0 |          0 |      0 | 1.4142135623731 |          3.2
  (1 row)
  
+ --
+ -- Test the SP-GiST index
+ --
+ CREATE TEMPORARY 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 TEMP 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 TEMP 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;
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
new file mode 100644
index 7ac8079..c58277b
*** a/src/test/regress/sql/polygon.sql
--- b/src/test/regress/sql/polygon.sql
*************** SELECT	'(0,0)'::point <-> '((0,0),(1,2),
*** 116,118 ****
--- 116,211 ----
  	'(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 TEMPORARY 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 TEMP 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 TEMP 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;
