point_ops for GiST

Started by Teodor Sigaevabout 16 years ago16 messages
#1Teodor Sigaev
teodor@sigaev.ru
1 attachment(s)

Hi!

patch implements operator class for GiST over points. Supported operations:
point << point
point >> point
point <^ point
point >^ point
point ~= point
point <@ box
box @> point
point <@ polygon
polygon @> point
point <@ circle
circle @> point
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/

Attachments:

point_ops-0.4.gzapplication/x-tar; name=point_ops-0.4.gzDownload
���
K�<is�X���_q�������%a�8��Un���uw�zM�p���A"6o�����E+�08=�j��t�=�9��EL������@�k�-�'�������O�����1��������|��O��d����*:A��v]Q����#�:�z"/t,k��W��+�M��;����5TG�e��T�VSG��En(��"���!����h�~\����W�{K��������Q�{z���q-��OY�{�_>�;�w4'����0<��?|�>^��Gg����@
�����p�`���X�7H�n�t��
����y=�
DX��k�DD���66���
b��1'!s�/M�^1�]�gA@Gw��C�;=���;��F1�, ��J�T������z�GLt����^#��B`����f�M?��#|dtC(�PJ�r,_��%��}��(o"��I^��(�yn�px�N��|8���E�D���bBr'���X)��|��� �k�����0#�����[a�x��^>���e���,�
,��FG�p��}^b 
��#QX�����i{8�{����"F��@{	c��h0��S?�F��2�����E O-t�$!J��}� �-���U��Z�u���������7B�
������ �&:����|����.3m�����5�9[��� ����o�
�#����3A6uy�Z���PLv_��������5�S��<�3�7��_:������ajD��K��d�B�.�XX���,$-���``:3�K�-	{�p�s!I(DP����u�������8J+`����!F��LA�)��#�P��P���\t���{<�D���������0B�B�NQ�iS�0�"��<��BIb��[>[����eFW��|TY�b2���5��6G7��BL��X����l�N�!���E������3�-�9����Q��xSZ�yj������{6��#H��t|���_��6�)�Mu����uU���y!?���&.
��M�����5"!@�$(0n)�Jm�%[�Z�.j���]M���Q��
�4���^�uO+�t���k��Y�e:���O��\�:�b��*����w�>z�e��-g��B&��u���@;�X)�9�	p���#��X���1��3��_DaQ#���.f#s��J4BY�U�c�������3�g8K%7`�� d;���,���{��(��/w�\������U/+�X��CnL9�:������<�"o���j~��������y�-�^��]-}��N��:����{������U���%��u���U9�+WZ��TY��_3Z����f�dE����`q/�e��qw�kY(>��u���I�_a`KG(�(B$O�/��#?U�5��l�~��r<r<%���C7���"kd.H<7�{D�����{���D�d�����-��S�
�����	�r9E�;z�������"q�pM�fa���=���2�I�S[��^N����M���ld>���{�a��I���p�v�;W��w�VG���FK��V+rer�!��#C�~&ZI�HT���n�F����*4[�Q����K�d�e�"����&*�V�"���� Cn�_4�fUh�@�*��r�*tpC�Rh�B�M�tM��\�J9�N�����Vt��F�R�7��ApW�
�Ap�5������-���|�.|/(,�;%^�Id�����d���n��x�7J�)��E(����P�	�i
�`���	�Yx��6�����$��ja
c%H�F����PZ�*�:�)WK�Tw�T�@6	�%G6��`������|l�����!@�_���:v�
<�)KJ��y6����l]���s�/�MrYf����B���{����
r����]�
A0�����?�����9d2�-�;'{������w�5h�p@Lug~C\��Hr�	s�������|:���`�>���U�,��Y�: Pd�}�2��8�y��(�������{y&&�����)���j>[Hj�j{C���nw��q���)��l�E@2���jA6���g�������?]�^��0���_���;��<�P���)��J)E�4�g�?��s���D&��B"Z$�f��:��3�V����� es�B���v�M�D�`���� &���Ne�+��%�-�����d���l++������9C��d]� &�eD�d��Z���H%t�p�!��_83����5Z�I���
�6H�MD��%.
:ib�"������O�/��
���"�P� ���G����H�<H D�F�Lw	?��'t[��F�L
=&a����L	�V)��
(���`�Z	�v������"T��c�6z�_n��0a�GB����X�:iC�������**69v%�Q�U�lFu7Q�?N�PTm2�����*�`&X���L�#�MI��+d����f�d}m>�^��y��T�bO#k��{������ T"Kf�|�n.�&����/��5��g;Xp��Y�w��t+���f=w��\���tY�m����n����!6Ur��9:V�����x��"0�(�7dZvO�R���>���G#gi�����l�!������y��R�C�|�re�Iz���8��{������,iWm���D�uu��_lMS'[��
����/��!�{y&��Am�<���ZJE��jKA�����(T�vZ�,K���@���/ C�@�W��^!8<T.��=�
Bw����J%2�=C���/.���f
��Dtf����s^!��pTe.\�"������49�1�c;�-���=2�����zNO�eX���( O$3����'rt��
AYGG�������
����;�d��i��^����4P?T���3&'���'0�l@�W����.���|���x������xd9�t�.}�
�@�NX�O�G�?��������vPD�`r:'�]�|�;�������hFN��@����S���N�����`�B�{����(��I�G��F����0U2�2'�=��fv<^�	�R$�WLo���
��]�B~i��[rj^�����0�>&/����>�?"�v����������$��9�����}(*+���v�j��kEQ%E�RSMR��S����QA�����q���B��������=���������9!�C�W������G^�A���qeZT��.����\\��jMUI�K�!KFp�A������q�:�k��bj��������P|M$?�%�v,V�P�[����D�V'�����Ju��BuCBuE�L ���;�dF����_���W�6:b���FV��Z����j���.��rq��|suu�x����j�IKY�|�
~A@�:�9��F/B�l���^F����N4�n���9.
:�mBa���.��3����w�C4�t:��jbe����<�l����Yqz��m�m-&�3m��q�8�f���*���l��G���x��Vq�M
���,��y���gen��d�x+���d|��J�M
�{mg,4/4�k-4���f�]�����*���BL��Yh�I�b(cF��[�����fv���Z��[m5-��B����@�HT���h��Ao}M�U�~����-&l���#�t,U��������u��FG�;F�M���I�F;8V��#v_�����o� �py��k�"$� 
\~�v�@TrPB./��2&
9�����qpP���|�-�(F���Ady�������nc����g��{�G�m������	O���w+����_�G���O6{�?���1\����}������:.`��\{�c{����Z���� |,� �<d"�[���d��H���L��eXi�Nw\�k1v������Tm2�+��Z���Kq��8�8i��I����F�"�K���X�`��U��D�|Yl��bU�>0�?�mt����������%�u�X���b��*(�
WI�Dk"���TM�H������"ZK'n'���'F��BH��q���H�elz�����0Y���E��B�E��7��,7%EUCTW��`5��'��:\�,�$T�9L��$=u�U�)��<���$����>��>�"@���~�����
��_(���0+/G��MJ�?
Z%
��� ����x#:j��F�7������W���"?h^�c����^���^%�@�T�������@�0�k����������L�K�$����V�{���<�7�}-�������������t�j>�lH���qr��9(�#�u�8F�{8
 J��&��(��i0s�dS^��rp��V��
�\������9��H
�����������?�~}�����G�^���}0�b���%����k�!�R'�v�/u�f')��<;�����\�Q�|������lKo��_d/v�q�E6 �|^b�m���3����W��,���)E��\"�5Oq�e#�@@�]s��^fi������}t��8����/A�j{W���&��]/h}�%�H�C�l
#2Greg Stark
gsstark@mit.edu
In reply to: Teodor Sigaev (#1)
Re: point_ops for GiST

2009/11/23 Teodor Sigaev <teodor@sigaev.ru>:

point   <@ box
point   <@ polygon
point   <@ circle

I've always wondered why we didn't have these

--
greg

#3Teodor Sigaev
teodor@sigaev.ru
In reply to: Teodor Sigaev (#1)
1 attachment(s)
Re: point_ops for GiST

Sync with current CVS

--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/

Attachments:

point_ops-0.5.gzapplication/x-tar; name=point_ops-0.5.gzDownload
#4Robert Haas
robertmhaas@gmail.com
In reply to: Teodor Sigaev (#3)
2 attachment(s)
Re: point_ops for GiST

2009/12/30 Teodor Sigaev <teodor@sigaev.ru>:

Sync with current CVS

I have reviewed this patch and it looks good to me. The only
substantive question I have is why gist_point_consistent() uses a
different coding pattern for the box case than it does for the polygon
and circle cases? It's not obvious to me on the face of it why these
aren't consistent.

Beyond that, I have a variety of minor whitespace and commenting
suggestions, so I am attaching an updated version of the patch as well
as an incremental diff between your version and mine, for your
consideration. The changes are: (1) comment reuse of gist_box
functions for point_ops, (2) format point ops function analogously to
existing sections in same file, (3) uncuddle opening braces, (4)
adjust indentation and spacing in a few places, (5) rename
StrategyNumberOffsetRange to GeoStrategyNumberOffset, and (6) use a
plain block instead of do {} while (0) - the latter construct is
really only needed in certain types of macros.

...Robert

Attachments:

point_ops-0.5-rmhapplication/octet-stream; name=point_ops-0.5-rmhDownload
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index bfa098d..0ebec52 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -165,7 +165,8 @@ gist_box_compress(PG_FUNCTION_ARGS)
 }
 
 /*
- * GiST DeCompress method for boxes (also used for polygons and circles)
+ * GiST DeCompress method for boxes (also used for points, polygons
+ * and circles)
  *
  * do not do anything --- we just use the stored box as is.
  */
@@ -176,7 +177,7 @@ gist_box_decompress(PG_FUNCTION_ARGS)
 }
 
 /*
- * The GiST Penalty method for boxes
+ * The GiST Penalty method for boxes (also used for points)
  *
  * As in the R-tree paper, we use change in area as our penalty metric
  */
@@ -341,6 +342,8 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
  *
  * New linear algorithm, see 'New Linear Node Splitting Algorithm for R-tree',
  * C.H.Ang and T.C.Tan
+ *
+ * This is used for both boxes and points.
  */
 Datum
 gist_box_picksplit(PG_FUNCTION_ARGS)
@@ -533,6 +536,8 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 /*
  * Equality method
+ *
+ * This is used for both boxes and points.
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
@@ -872,3 +877,166 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(result);
 }
+
+/**************************************************
+ * Point ops
+ **************************************************/
+
+Datum
+gist_point_compress(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	if (entry->leafkey)			/* Point, actually */
+	{
+		BOX	   *box = palloc(sizeof(BOX));
+		Point  *point = DatumGetPointP(entry->key);
+		GISTENTRY  *retval = palloc(sizeof(GISTENTRY));
+
+		box->high = box->low = *point;
+
+		gistentryinit(*retval, BoxPGetDatum(box),
+					  entry->rel, entry->page, entry->offset, FALSE);
+
+		PG_RETURN_POINTER(retval);
+	}
+
+	PG_RETURN_POINTER(entry);
+}
+
+static bool
+gist_point_consistent_internal(StrategyNumber strategy,
+										   bool isLeaf, BOX *key, Point *query)
+{
+	bool result = false;
+
+	switch (strategy)
+	{
+		case RTLeftStrategyNumber:
+			result = FPlt(key->low.x, query->x);
+			break;
+		case RTRightStrategyNumber:
+			result = FPgt(key->high.x, query->x);
+			break;
+		case RTAboveStrategyNumber:
+			result = FPgt(key->high.y, query->y);
+			break;
+		case RTBelowStrategyNumber:
+			result = FPlt(key->low.y, query->y);
+			break;
+		case RTSameStrategyNumber:
+			if (isLeaf)
+			{
+				result = FPeq(key->low.x, query->x)
+					&& FPeq(key->low.y, query->y);
+			}
+			else
+			{
+				result = (query->x <= key->high.x && query->x >= key->low.x &&
+						  query->y <= key->high.y && query->y >= key->low.y);
+			}
+			break;
+		default:
+			elog(ERROR, "unknown strategy number: %d", strategy);
+	}
+
+	return result;
+}
+
+#define GeoStrategyNumberOffset		20
+#define PointStrategyNumberGroup	0
+#define BoxStrategyNumberGroup		1
+#define PolygonStrategyNumberGroup	2
+#define CircleStrategyNumberGroup	3
+
+Datum
+gist_point_consistent(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	StrategyNumber	strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+	bool		result;
+	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	StrategyNumber	strategyGroup = strategy / GeoStrategyNumberOffset;
+
+	switch (strategyGroup)
+	{
+		case PointStrategyNumberGroup:
+			result = gist_point_consistent_internal(strategy % GeoStrategyNumberOffset,
+													GIST_LEAF(entry),
+													DatumGetBoxP(entry->key),
+													PG_GETARG_POINT_P(1));
+			*recheck = false;
+			break;
+		case BoxStrategyNumberGroup:
+			result = DatumGetBool(DirectFunctionCall5(
+											gist_box_consistent,
+											PointerGetDatum(entry),
+											PG_GETARG_DATUM(1),
+											Int16GetDatum(RTOverlapStrategyNumber),
+											0, PointerGetDatum(recheck)));
+			break;
+		case PolygonStrategyNumberGroup:
+			{
+				POLYGON    *query = PG_GETARG_POLYGON_P(1);
+
+				result = DatumGetBool(DirectFunctionCall5(
+												gist_poly_consistent,
+												PointerGetDatum(entry),
+												PolygonPGetDatum(query),
+												Int16GetDatum(RTOverlapStrategyNumber),
+												0, PointerGetDatum(recheck)));
+
+				if (GIST_LEAF(entry) && result)
+				{
+					/*
+					 * We are on leaf page and quick check shows overlapping
+					 * of polygon's bounding box and point
+					 */
+					BOX *box = DatumGetBoxP(entry->key);
+
+					Assert(box->high.x == box->low.x
+						&& box->high.y == box->low.y);
+					result = DatumGetBool(DirectFunctionCall2(
+												poly_contain_pt,
+												PolygonPGetDatum(query),
+												PointPGetDatum(&box->high)));
+					*recheck = false;
+				}
+			}
+			break;
+		case CircleStrategyNumberGroup:
+			{
+				CIRCLE *query = PG_GETARG_CIRCLE_P(1);
+
+				result = DatumGetBool(DirectFunctionCall5(
+												gist_circle_consistent,
+												PointerGetDatum(entry),
+												CirclePGetDatum(query),
+												Int16GetDatum(RTOverlapStrategyNumber),
+												0, PointerGetDatum(recheck)));
+
+				if (GIST_LEAF(entry) && result)
+				{
+					/*
+					 * We are on leaf page and quick check shows overlapping
+					 * of polygon's bounding box and point
+					 */
+					BOX *box = DatumGetBoxP(entry->key);
+
+					Assert(box->high.x == box->low.x
+						&& box->high.y == box->low.y);
+					result = DatumGetBool(DirectFunctionCall2(
+												circle_contain_pt,
+												CirclePGetDatum(query),
+												PointPGetDatum(&box->high)));
+					*recheck = false;
+				}
+			}
+			break;
+		default:
+			result = false;			/* silence compiler warning */
+			elog(ERROR, "unknown strategy number: %d", strategy);
+	}
+
+	PG_RETURN_BOOL(result);
+}
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index e9e6b35..eda1d35 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -3202,6 +3202,16 @@ on_pb(PG_FUNCTION_ARGS)
 				   pt->y <= box->high.y && pt->y >= box->low.y);
 }
 
+Datum
+box_contain_pt(PG_FUNCTION_ARGS) 
+{
+	BOX		   *box = PG_GETARG_BOX_P(0);
+	Point	   *pt = PG_GETARG_POINT_P(1);
+
+	PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x &&
+				   pt->y <= box->high.y && pt->y >= box->low.y);
+}
+
 /* on_ppath -
  *		Whether a point lies within (on) a polyline.
  *		If open, we have to (groan) check each segment.
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 9138bbc..fb0dbd3 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -583,6 +583,22 @@ DATA(insert (	2593   603 603 13 2863	783 ));
 DATA(insert (	2593   603 603 14 2862	783 ));
 
 /*
+ * gist point_ops
+ */
+DATA(insert (	1029   600 600 11 506 783 ));
+DATA(insert (	1029   600 600 1  507 783 ));
+DATA(insert (	1029   600 600 5  508 783 ));
+DATA(insert (	1029   600 600 10 509 783 ));
+DATA(insert (	1029   600 600 6  510 783 ));
+DATA(insert (	1029   603 600 27  433 783 ));
+DATA(insert (	1029   600 603 28  511 783 ));
+DATA(insert (	1029   604 600 47 757 783 ));
+DATA(insert (	1029   600 604 48 756 783 ));
+DATA(insert (	1029   718 600 67 759 783 ));
+DATA(insert (	1029   600 718 68 758 783 ));
+
+
+/*
  *	gist poly_ops (supports polygons)
  */
 
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index 2bd2fd5..f1a4278 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -197,6 +197,13 @@ DATA(insert (	3702   3615 3615 4 3696 ));
 DATA(insert (	3702   3615 3615 5 3700 ));
 DATA(insert (	3702   3615 3615 6 3697 ));
 DATA(insert (	3702   3615 3615 7 3699 ));
+DATA(insert (	1029   600 600 1 2179 ));
+DATA(insert (	1029   600 600 2 2583 ));
+DATA(insert (	1029   600 600 3 1030 ));
+DATA(insert (	1029   600 600 4 2580 ));
+DATA(insert (	1029   600 600 5 2581 ));
+DATA(insert (	1029   600 600 6 2582 ));
+DATA(insert (	1029   600 600 7 2584 ));
 
 
 /* gin */
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 2e106f9..e98afbe 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -170,6 +170,7 @@ DATA(insert (	403		reltime_ops			PGNSP PGUID 2233  703 t 0 ));
 DATA(insert (	403		tinterval_ops		PGNSP PGUID 2234  704 t 0 ));
 DATA(insert (	405		aclitem_ops			PGNSP PGUID 2235 1033 t 0 ));
 DATA(insert (	783		box_ops				PGNSP PGUID 2593  603 t 0 ));
+DATA(insert (	783		point_ops			PGNSP PGUID 1029  600 t 603 ));
 DATA(insert (	783		poly_ops			PGNSP PGUID 2594  604 t 603 ));
 DATA(insert (	783		circle_ops			PGNSP PGUID 2595  718 t 603 ));
 DATA(insert (	2742	_int4_ops			PGNSP PGUID 2745  1007 t 23 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index eb079dd..f117d66 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -171,7 +171,8 @@ DATA(insert OID = 507 (  "<<"	   PGNSP PGUID b f f 600 600	16	 0	 0 point_left p
 DATA(insert OID = 508 (  ">>"	   PGNSP PGUID b f f 600 600	16	 0	 0 point_right positionsel positionjoinsel ));
 DATA(insert OID = 509 (  "<^"	   PGNSP PGUID b f f 600 600	16	 0	 0 point_below positionsel positionjoinsel ));
 DATA(insert OID = 510 (  "~="	   PGNSP PGUID b f f 600 600	16 510 713 point_eq eqsel eqjoinsel ));
-DATA(insert OID = 511 (  "<@"	   PGNSP PGUID b f f 600 603	16	 0	 0 on_pb - - ));
+DATA(insert OID = 511 (  "<@"	   PGNSP PGUID b f f 600 603	16 433	 0 on_pb contsel contjoinsel ));
+DATA(insert OID = 433 (  "@>"	   PGNSP PGUID b f f 603 600	16 511	 0 box_contain_pt contsel contjoinsel ));
 DATA(insert OID = 512 (  "<@"	   PGNSP PGUID b f f 600 602	16 755	 0 on_ppath - - ));
 DATA(insert OID = 513 (  "@@"	   PGNSP PGUID l f f	 0 603 600	 0	 0 box_center - - ));
 DATA(insert OID = 514 (  "*"	   PGNSP PGUID b f f	23	23	23 514	 0 int4mul - - ));
@@ -359,10 +360,10 @@ DATA(insert OID = 737 (  "-"	   PGNSP PGUID b f f	602  600	602    0  0 path_sub_
 DATA(insert OID = 738 (  "*"	   PGNSP PGUID b f f	602  600	602    0  0 path_mul_pt - - ));
 DATA(insert OID = 739 (  "/"	   PGNSP PGUID b f f	602  600	602    0  0 path_div_pt - - ));
 DATA(insert OID = 755 (  "@>"	   PGNSP PGUID b f f	602  600	 16  512  0 path_contain_pt - - ));
-DATA(insert OID = 756 (  "<@"	   PGNSP PGUID b f f	600  604	 16  757  0 pt_contained_poly - - ));
-DATA(insert OID = 757 (  "@>"	   PGNSP PGUID b f f	604  600	 16  756  0 poly_contain_pt - - ));
-DATA(insert OID = 758 (  "<@"	   PGNSP PGUID b f f	600  718	 16  759  0 pt_contained_circle - - ));
-DATA(insert OID = 759 (  "@>"	   PGNSP PGUID b f f	718  600	 16  758  0 circle_contain_pt - - ));
+DATA(insert OID = 756 (  "<@"	   PGNSP PGUID b f f	600  604	 16  757  0 pt_contained_poly contsel contjoinsel ));
+DATA(insert OID = 757 (  "@>"	   PGNSP PGUID b f f	604  600	 16  756  0 poly_contain_pt contsel contjoinsel ));
+DATA(insert OID = 758 (  "<@"	   PGNSP PGUID b f f	600  718	 16  759  0 pt_contained_circle contsel contjoinsel ));
+DATA(insert OID = 759 (  "@>"	   PGNSP PGUID b f f	718  600	 16  758  0 circle_contain_pt contsel contjoinsel ));
 
 DATA(insert OID = 773 (  "@"	   PGNSP PGUID l f f	 0	23	23	 0	 0 int4abs - - ));
 
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 9be6bed..133a27b 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -127,6 +127,7 @@ DATA(insert OID = 2235 (	405		aclitem_ops		PGNSP PGUID ));
 DATA(insert OID = 2593 (	783		box_ops			PGNSP PGUID ));
 DATA(insert OID = 2594 (	783		poly_ops		PGNSP PGUID ));
 DATA(insert OID = 2595 (	783		circle_ops		PGNSP PGUID ));
+DATA(insert OID = 1029 (	783		point_ops		PGNSP PGUID ));
 DATA(insert OID = 2745 (	2742	array_ops		PGNSP PGUID ));
 DATA(insert OID = 2968 (	403		uuid_ops		PGNSP PGUID ));
 DATA(insert OID = 2969 (	405		uuid_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 8fe9dec..2e11c79 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -396,6 +396,8 @@ DATA(insert OID = 191 (  box_right		   PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "
 DESCR("is right of");
 DATA(insert OID = 192 (  box_contained	   PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "603 603" _null_ _null_ _null_ _null_ box_contained _null_ _null_ _null_ ));
 DESCR("is contained by?");
+DATA(insert OID = 193 (  box_contain_pt	   PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ box_contain_pt _null_ _null_ _null_ ));
+DESCR("contains?");
 
 /* OIDS 200 - 299 */
 
@@ -4205,6 +4207,10 @@ DATA(insert OID = 2591 (  gist_circle_consistent PGNSP PGUID 12 1 0 0 f f f t f
 DESCR("GiST support");
 DATA(insert OID = 2592 (  gist_circle_compress	PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ gist_circle_compress _null_ _null_ _null_ ));
 DESCR("GiST support");
+DATA(insert OID = 1030 (  gist_point_compress	PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ gist_point_compress _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 2179 (  gist_point_consistent	PGNSP PGUID 12 1 0 0 f f f t f i 5 0 16 "2281 603 23 26 2281" _null_ _null_ _null_ _null_	gist_point_consistent _null_ _null_ _null_ ));
+DESCR("GiST support");
 
 /* GIN */
 DATA(insert OID = 2731 (  gingetbitmap	   PGNSP PGUID 12 1 0 0 f f f t f v 2 0 20 "2281 2281" _null_ _null_ _null_ _null_	gingetbitmap _null_ _null_ _null_ ));
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index a64f06f..091fce1 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -290,6 +290,7 @@ extern Datum box_above(PG_FUNCTION_ARGS);
 extern Datum box_overabove(PG_FUNCTION_ARGS);
 extern Datum box_contained(PG_FUNCTION_ARGS);
 extern Datum box_contain(PG_FUNCTION_ARGS);
+extern Datum box_contain_pt(PG_FUNCTION_ARGS);
 extern Datum box_below_eq(PG_FUNCTION_ARGS);
 extern Datum box_above_eq(PG_FUNCTION_ARGS);
 extern Datum box_lt(PG_FUNCTION_ARGS);
@@ -420,6 +421,8 @@ extern Datum gist_poly_compress(PG_FUNCTION_ARGS);
 extern Datum gist_poly_consistent(PG_FUNCTION_ARGS);
 extern Datum gist_circle_compress(PG_FUNCTION_ARGS);
 extern Datum gist_circle_consistent(PG_FUNCTION_ARGS);
+extern Datum gist_point_compress(PG_FUNCTION_ARGS);
+extern Datum gist_point_consistent(PG_FUNCTION_ARGS);
 
 /* geo_selfuncs.c */
 extern Datum areasel(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 9dd54b3..8819011 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -51,6 +51,7 @@ CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops)
 CREATE INDEX grect2ind ON fast_emp4000 USING gist (home_base);
 CREATE INDEX gpolygonind ON polygon_tbl USING gist (f1);
 CREATE INDEX gcircleind ON circle_tbl USING gist (f1);
+CREATE INDEX gpointind ON point_tbl USING gist (f1);
 CREATE TEMP TABLE gpolygon_tbl AS
     SELECT polygon(home_base) AS f1 FROM slow_emp4000;
 INSERT INTO gpolygon_tbl VALUES ( '(1000,0,0,1000)' ); 
@@ -112,6 +113,60 @@ SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
      2
 (1 row)
 
+SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
+ count 
+-------
+     3
+(1 row)
+
+SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
+ count 
+-------
+     3
+(1 row)
+
+SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
+ count 
+-------
+     3
+(1 row)
+
+SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
+ count 
+-------
+     3
+(1 row)
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
+ count 
+-------
+     2
+(1 row)
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
+ count 
+-------
+     3
+(1 row)
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
+ count 
+-------
+     1
+(1 row)
+
 SET enable_seqscan = OFF;
 SET enable_indexscan = ON;
 SET enable_bitmapscan = ON;
@@ -245,6 +300,141 @@ SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
      2
 (1 row)
 
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
+                     QUERY PLAN                     
+----------------------------------------------------
+ Aggregate
+   ->  Index Scan using gpointind on point_tbl
+         Index Cond: (f1 <@ '(100,100),(0,0)'::box)
+(3 rows)
+
+SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
+ count 
+-------
+     3
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
+                     QUERY PLAN                     
+----------------------------------------------------
+ Aggregate
+   ->  Index Scan using gpointind on point_tbl
+         Index Cond: ('(100,100),(0,0)'::box @> f1)
+(3 rows)
+
+SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
+ count 
+-------
+     3
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
+                                       QUERY PLAN                                       
+----------------------------------------------------------------------------------------
+ Aggregate
+   ->  Index Scan using gpointind on point_tbl
+         Index Cond: (f1 <@ '((0,0),(0,100),(100,100),(50,50),(100,0),(0,0))'::polygon)
+(3 rows)
+
+SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
+ count 
+-------
+     3
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
+                     QUERY PLAN                     
+----------------------------------------------------
+ Aggregate
+   ->  Index Scan using gpointind on point_tbl
+         Index Cond: (f1 <@ '<(50,50),50>'::circle)
+(3 rows)
+
+SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
+ count 
+-------
+     1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Aggregate
+   ->  Index Scan using gpointind on point_tbl p
+         Index Cond: (f1 << '(0,0)'::point)
+(3 rows)
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
+ count 
+-------
+     3
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Aggregate
+   ->  Index Scan using gpointind on point_tbl p
+         Index Cond: (f1 >> '(0,0)'::point)
+(3 rows)
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
+ count 
+-------
+     2
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Aggregate
+   ->  Index Scan using gpointind on point_tbl p
+         Index Cond: (f1 <^ '(0,0)'::point)
+(3 rows)
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
+ count 
+-------
+     1
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Aggregate
+   ->  Index Scan using gpointind on point_tbl p
+         Index Cond: (f1 >^ '(0,0)'::point)
+(3 rows)
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
+ count 
+-------
+     3
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Aggregate
+   ->  Index Scan using gpointind on point_tbl p
+         Index Cond: (f1 ~= '(-5,-12)'::point)
+(3 rows)
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
+ count 
+-------
+     1
+(1 row)
+
 RESET enable_seqscan;
 RESET enable_indexscan;
 RESET enable_bitmapscan;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 24a2e8a..5e36d48 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -902,17 +902,25 @@ ORDER BY 1, 2, 3;
         783 |            8 | <@
         783 |            9 | &<|
         783 |           10 | <<|
+        783 |           10 | <^
+        783 |           11 | >^
         783 |           11 | |>>
         783 |           12 | |&>
         783 |           13 | ~
         783 |           14 | @
+        783 |           27 | @>
+        783 |           28 | <@
+        783 |           47 | @>
+        783 |           48 | <@
+        783 |           67 | @>
+        783 |           68 | <@
        2742 |            1 | &&
        2742 |            1 | @@
        2742 |            2 | @>
        2742 |            2 | @@@
        2742 |            3 | <@
        2742 |            4 | =
-(31 rows)
+(39 rows)
 
 -- Check that all operators linked to by opclass entries have selectivity
 -- estimators.  This is not absolutely required, but it seems a reasonable
diff --git a/src/test/regress/expected/point.out b/src/test/regress/expected/point.out
index 9d1bd43..278837d 100644
--- a/src/test/regress/expected/point.out
+++ b/src/test/regress/expected/point.out
@@ -82,6 +82,15 @@ SELECT '' AS three, p.* FROM POINT_TBL p
 (3 rows)
 
 SELECT '' AS three, p.* FROM POINT_TBL p
+   WHERE box '(0,0,100,100)' @> p.f1;
+ three |     f1     
+-------+------------
+       | (0,0)
+       | (5.1,34.5)
+       | (10,10)
+(3 rows)
+
+SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not p.f1 <@ box '(0,0,100,100)';
  three |    f1    
 -------+----------
@@ -98,6 +107,15 @@ SELECT '' AS two, p.* FROM POINT_TBL p
      | (-10,0)
 (2 rows)
 
+SELECT '' AS three, p.* FROM POINT_TBL p
+   WHERE not box '(0,0,100,100)' @> p.f1;
+ three |    f1    
+-------+----------
+       | (-10,0)
+       | (-3,4)
+       | (-5,-12)
+(3 rows)
+
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 2a4dc47..4dc59d9 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -127,7 +127,7 @@ SELECT relname, relhasindex
  pg_ts_template          | t
  pg_type                 | t
  pg_user_mapping         | t
- point_tbl               | f
+ point_tbl               | t
  polygon_tbl             | t
  ramp                    | f
  real_city               | f
diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql
index b205afa..47b93de 100644
--- a/src/test/regress/sql/create_index.sql
+++ b/src/test/regress/sql/create_index.sql
@@ -76,6 +76,8 @@ CREATE INDEX gpolygonind ON polygon_tbl USING gist (f1);
 
 CREATE INDEX gcircleind ON circle_tbl USING gist (f1);
 
+CREATE INDEX gpointind ON point_tbl USING gist (f1);
+
 CREATE TEMP TABLE gpolygon_tbl AS
     SELECT polygon(home_base) AS f1 FROM slow_emp4000;
 INSERT INTO gpolygon_tbl VALUES ( '(1000,0,0,1000)' ); 
@@ -110,6 +112,24 @@ SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon;
 
 SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
 
+SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
+
+SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
+
+SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
+
+SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
+
+SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
+
 SET enable_seqscan = OFF;
 SET enable_indexscan = ON;
 SET enable_bitmapscan = ON;
@@ -150,6 +170,42 @@ EXPLAIN (COSTS OFF)
 SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
 SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
 
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
+SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
+SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
+SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
+SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
+SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
+SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
+SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
+SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
+SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
+
 RESET enable_seqscan;
 RESET enable_indexscan;
 RESET enable_bitmapscan;
diff --git a/src/test/regress/sql/point.sql b/src/test/regress/sql/point.sql
index 8523c2e..40cd4ec 100644
--- a/src/test/regress/sql/point.sql
+++ b/src/test/regress/sql/point.sql
@@ -46,11 +46,17 @@ SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE p.f1 <@ box '(0,0,100,100)';
 
 SELECT '' AS three, p.* FROM POINT_TBL p
+   WHERE box '(0,0,100,100)' @> p.f1;
+
+SELECT '' AS three, p.* FROM POINT_TBL p
    WHERE not p.f1 <@ box '(0,0,100,100)';
 
 SELECT '' AS two, p.* FROM POINT_TBL p
    WHERE p.f1 <@ path '[(0,0),(-10,0),(-10,10)]';
 
+SELECT '' AS three, p.* FROM POINT_TBL p
+   WHERE not box '(0,0,100,100)' @> p.f1;
+
 SELECT '' AS six, p.f1, p.f1 <-> point '(0,0)' AS dist
    FROM POINT_TBL p
    ORDER BY dist;
point_ops-0.5-rmh-incrementalapplication/octet-stream; name=point_ops-0.5-rmh-incrementalDownload
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 1795a71..0ebec52 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -165,7 +165,8 @@ gist_box_compress(PG_FUNCTION_ARGS)
 }
 
 /*
- * GiST DeCompress method for boxes (also used for polygons and circles)
+ * GiST DeCompress method for boxes (also used for points, polygons
+ * and circles)
  *
  * do not do anything --- we just use the stored box as is.
  */
@@ -176,7 +177,7 @@ gist_box_decompress(PG_FUNCTION_ARGS)
 }
 
 /*
- * The GiST Penalty method for boxes
+ * The GiST Penalty method for boxes (also used for points)
  *
  * As in the R-tree paper, we use change in area as our penalty metric
  */
@@ -341,6 +342,8 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
  *
  * New linear algorithm, see 'New Linear Node Splitting Algorithm for R-tree',
  * C.H.Ang and T.C.Tan
+ *
+ * This is used for both boxes and points.
  */
 Datum
 gist_box_picksplit(PG_FUNCTION_ARGS)
@@ -533,6 +536,8 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 
 /*
  * Equality method
+ *
+ * This is used for both boxes and points.
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
@@ -873,25 +878,25 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(result);
 }
 
-
-
-/*
- * Point
- */
+/**************************************************
+ * Point ops
+ **************************************************/
 
 Datum
-gist_point_compress(PG_FUNCTION_ARGS) {
+gist_point_compress(PG_FUNCTION_ARGS)
+{
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 
-	if ( entry->leafkey ) { /* Point, actually */
-		BOX		 *box = palloc(sizeof(BOX));
-		Point	   *point = DatumGetPointP(entry->key);
-		GISTENTRY   *retval = palloc(sizeof(GISTENTRY));
+	if (entry->leafkey)			/* Point, actually */
+	{
+		BOX	   *box = palloc(sizeof(BOX));
+		Point  *point = DatumGetPointP(entry->key);
+		GISTENTRY  *retval = palloc(sizeof(GISTENTRY));
 
 		box->high = box->low = *point;
 
 		gistentryinit(*retval, BoxPGetDatum(box),
-					entry->rel, entry->page, entry->offset, FALSE);
+					  entry->rel, entry->page, entry->offset, FALSE);
 
 		PG_RETURN_POINTER(retval);
 	}
@@ -900,11 +905,12 @@ gist_point_compress(PG_FUNCTION_ARGS) {
 }
 
 static bool
-gist_point_consistent_internal(StrategyNumber strategy, bool isLeaf, BOX *key, Point *query)
+gist_point_consistent_internal(StrategyNumber strategy,
+										   bool isLeaf, BOX *key, Point *query)
 {
 	bool result = false;
 
-	switch( strategy )
+	switch (strategy)
 	{
 		case RTLeftStrategyNumber:
 			result = FPlt(key->low.x, query->x);
@@ -921,7 +927,8 @@ gist_point_consistent_internal(StrategyNumber strategy, bool isLeaf, BOX *key, P
 		case RTSameStrategyNumber:
 			if (isLeaf)
 			{
-				result = FPeq(key->low.x, query->x) && FPeq(key->low.y, query->y);
+				result = FPeq(key->low.x, query->x)
+					&& FPeq(key->low.y, query->y);
 			}
 			else
 			{
@@ -936,97 +943,100 @@ gist_point_consistent_internal(StrategyNumber strategy, bool isLeaf, BOX *key, P
 	return result;
 }
 
-#define	StrategyNumberOffsetRange	20
+#define GeoStrategyNumberOffset		20
 #define PointStrategyNumberGroup	0
 #define BoxStrategyNumberGroup		1
 #define PolygonStrategyNumberGroup	2
 #define CircleStrategyNumberGroup	3
 
 Datum
-gist_point_consistent(PG_FUNCTION_ARGS) {
+gist_point_consistent(PG_FUNCTION_ARGS)
+{
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
-	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+	StrategyNumber	strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 	bool		result;
 	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
-	StrategyNumber	strategyGroup = strategy / StrategyNumberOffsetRange;
+	StrategyNumber	strategyGroup = strategy / GeoStrategyNumberOffset;
 
-	switch(strategyGroup)
+	switch (strategyGroup)
 	{
-		case	PointStrategyNumberGroup:
-			result = gist_point_consistent_internal(strategy % StrategyNumberOffsetRange,
+		case PointStrategyNumberGroup:
+			result = gist_point_consistent_internal(strategy % GeoStrategyNumberOffset,
 													GIST_LEAF(entry),
 													DatumGetBoxP(entry->key),
 													PG_GETARG_POINT_P(1));
 			*recheck = false;
 			break;
-		case	BoxStrategyNumberGroup:
-			result = DatumGetBool( DirectFunctionCall5(
+		case BoxStrategyNumberGroup:
+			result = DatumGetBool(DirectFunctionCall5(
 											gist_box_consistent,
 											PointerGetDatum(entry),
 											PG_GETARG_DATUM(1),
 											Int16GetDatum(RTOverlapStrategyNumber),
 											0, PointerGetDatum(recheck)));
 			break;
-		case	PolygonStrategyNumberGroup:
-			do {
+		case PolygonStrategyNumberGroup:
+			{
 				POLYGON    *query = PG_GETARG_POLYGON_P(1);
 
-				result = DatumGetBool( DirectFunctionCall5(
+				result = DatumGetBool(DirectFunctionCall5(
 												gist_poly_consistent,
 												PointerGetDatum(entry),
 												PolygonPGetDatum(query),
 												Int16GetDatum(RTOverlapStrategyNumber),
 												0, PointerGetDatum(recheck)));
 
-				if ( GIST_LEAF(entry) && result ) {
+				if (GIST_LEAF(entry) && result)
+				{
 					/*
 					 * We are on leaf page and quick check shows overlapping
 					 * of polygon's bounding box and point
 					 */
 					BOX *box = DatumGetBoxP(entry->key);
 
-					Assert( box->high.x == box->low.x && box->high.y == box->low.y );
-
-					result = DatumGetBool( DirectFunctionCall2(
+					Assert(box->high.x == box->low.x
+						&& box->high.y == box->low.y);
+					result = DatumGetBool(DirectFunctionCall2(
 												poly_contain_pt,
 												PolygonPGetDatum(query),
 												PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
-			} while (0);
+			}
 			break;
-		case	CircleStrategyNumberGroup:
-			do {
+		case CircleStrategyNumberGroup:
+			{
 				CIRCLE *query = PG_GETARG_CIRCLE_P(1);
 
-				result = DatumGetBool( DirectFunctionCall5(
+				result = DatumGetBool(DirectFunctionCall5(
 												gist_circle_consistent,
 												PointerGetDatum(entry),
 												CirclePGetDatum(query),
 												Int16GetDatum(RTOverlapStrategyNumber),
 												0, PointerGetDatum(recheck)));
 
-				if ( GIST_LEAF(entry) && result ) {
+				if (GIST_LEAF(entry) && result)
+				{
 					/*
 					 * We are on leaf page and quick check shows overlapping
 					 * of polygon's bounding box and point
 					 */
 					BOX *box = DatumGetBoxP(entry->key);
 
-					Assert( box->high.x == box->low.x && box->high.y == box->low.y );
-
-					result = DatumGetBool( DirectFunctionCall2(
+					Assert(box->high.x == box->low.x
+						&& box->high.y == box->low.y);
+					result = DatumGetBool(DirectFunctionCall2(
 												circle_contain_pt,
 												CirclePGetDatum(query),
 												PointPGetDatum(&box->high)));
 					*recheck = false;
 				}
-			} while(0);
+			}
 			break;
 		default:
+			result = false;			/* silence compiler warning */
 			elog(ERROR, "unknown strategy number: %d", strategy);
 	}
 
 	PG_RETURN_BOOL(result);
 }
-
#5Teodor Sigaev
teodor@sigaev.ru
In reply to: Robert Haas (#4)
Re: point_ops for GiST

I have reviewed this patch and it looks good to me. The only
substantive question I have is why gist_point_consistent() uses a
different coding pattern for the box case than it does for the polygon
and circle cases? It's not obvious to me on the face of it why these
aren't consistent.

gist_circle_consistent/gist_poly_consistent set recheck flag to true because
corresponding index contains only bounding box of indexed values
(circle/polygon). gist_point_consistent could do an exact check. Will add a coments.

Beyond that, I have a variety of minor whitespace and commenting
suggestions, so I am attaching an updated version of the patch as well

Agree with your changes. Suppose, there is no objection to commit it?

--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/

#6Robert Haas
robertmhaas@gmail.com
In reply to: Teodor Sigaev (#5)
Re: point_ops for GiST

2010/1/11 Teodor Sigaev <teodor@sigaev.ru>:

I have reviewed this patch and it looks good to me.  The only
substantive question I have is why gist_point_consistent() uses a
different coding pattern for the box case than it does for the polygon
and circle cases?  It's not obvious to me on the face of it why these
aren't consistent.

gist_circle_consistent/gist_poly_consistent set recheck flag to true because
corresponding index contains only bounding box of indexed values
(circle/polygon). gist_point_consistent could do an exact check. Will add a
coments.

Make sense. A comment sounds good.

Beyond that, I have a variety of minor whitespace and commenting
suggestions, so I am attaching an updated version of the patch as well

Agree with your changes. Suppose, there is no objection to commit it?

No, I think it looks good... if no one else chimes in with objections
in the next day or two I would go ahead.

...Robert

#7Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Robert Haas (#4)
Re: point_ops for GiST

Robert Haas wrote:

2009/12/30 Teodor Sigaev <teodor@sigaev.ru>:

Sync with current CVS

I have reviewed this patch and it looks good to me. The only
substantive question I have is why gist_point_consistent() uses a
different coding pattern for the box case than it does for the polygon
and circle cases? It's not obvious to me on the face of it why these
aren't consistent.

Emre Hasegeli just pointed out to me that this patch introduced
box_contain_pt() and in doing so used straight C comparison (<= etc)
instead of FPlt() and friends. I would think that that's a bug and
needs to be changed -- but certainly not backpatched, because gist
indexes would/might become corrupt.

This is in the context of his inclusion opclass for BRIN
/messages/by-id/CAE2gYzwBZQ=z02ZiOefNhrXOf+1VegQC_cWPVJ8LwNqGX1--Ww@mail.gmail.com

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Alvaro Herrera (#7)
Re: point_ops for GiST

Alvaro Herrera wrote:

Robert Haas wrote:

2009/12/30 Teodor Sigaev <teodor@sigaev.ru>:

Sync with current CVS

I have reviewed this patch and it looks good to me. The only
substantive question I have is why gist_point_consistent() uses a
different coding pattern for the box case than it does for the polygon
and circle cases? It's not obvious to me on the face of it why these
aren't consistent.

Emre Hasegeli just pointed out to me that this patch introduced
box_contain_pt() and in doing so used straight C comparison (<= etc)
instead of FPlt() and friends.

(This is commit 4cbe473938779ec414d90c2063c4398e68a70838)

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Emre Hasegeli
emre@hasegeli.com
In reply to: Alvaro Herrera (#7)
Re: point_ops for GiST

Emre Hasegeli just pointed out to me that this patch introduced
box_contain_pt() and in doing so used straight C comparison (<= etc)
instead of FPlt() and friends. I would think that that's a bug and
needs to be changed -- but certainly not backpatched, because gist
indexes would/might become corrupt.

The problem with this is BRIN inclusion opclass uses some operators to
implement others. It was using box @> point operator to implement
point ~= point operator by indexing points in boxes. The former
doesn't use the macros, but later does. The opclass could return
wrong result when the point right near the index boundaries.

Currently, there are not BRIN opclasses for geometric types except box
because of this reason. I would like to work on supporting them for
the next release. I think the best way is to change the operators
which are not using the macros to be consistent with the others. Here
is the list:

* polygon << polygon
* polygon &< polygon
* polygon &> polygon
* polygon >> polygon
* polygon <<| polygon
* polygon &<| polygon
* polygon |&> polygon
* polygon |>> polygon
* box @> point
* point <@ box
* lseg <@ box
* circle @> point
* point <@ circle

I can send a patch, if it is acceptable.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Stefan Keller
sfkeller@gmail.com
In reply to: Emre Hasegeli (#9)
Re: point_ops for GiST

Hi Emre

Pls. don't misunderstand my questions: They are directed to get an
even more useful spatial data handling of PostgreSQL. I'm working with
PostGIS since years and are interested in any work regarding spatial
types...

Can anyone report use cases or applications of these built-in geometric types?

Would'nt it be even more useful to concentrate to PostGIS
geometry/geography types and extend BRIN to these types?

:Stefan

2015-06-13 23:04 GMT+02:00 Emre Hasegeli <emre@hasegeli.com>:

Emre Hasegeli just pointed out to me that this patch introduced
box_contain_pt() and in doing so used straight C comparison (<= etc)
instead of FPlt() and friends. I would think that that's a bug and
needs to be changed -- but certainly not backpatched, because gist
indexes would/might become corrupt.

The problem with this is BRIN inclusion opclass uses some operators to
implement others. It was using box @> point operator to implement
point ~= point operator by indexing points in boxes. The former
doesn't use the macros, but later does. The opclass could return
wrong result when the point right near the index boundaries.

Currently, there are not BRIN opclasses for geometric types except box
because of this reason. I would like to work on supporting them for
the next release. I think the best way is to change the operators
which are not using the macros to be consistent with the others. Here
is the list:

* polygon << polygon
* polygon &< polygon
* polygon &> polygon
* polygon >> polygon
* polygon <<| polygon
* polygon &<| polygon
* polygon |&> polygon
* polygon |>> polygon
* box @> point
* point <@ box
* lseg <@ box
* circle @> point
* point <@ circle

I can send a patch, if it is acceptable.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Alvaro Herrera (#7)
Re: point_ops for GiST

Hi, Alvaro!

On Tue, May 12, 2015 at 9:13 PM, Alvaro Herrera <alvherre@2ndquadrant.com>
wrote:

Robert Haas wrote:

2009/12/30 Teodor Sigaev <teodor@sigaev.ru>:

Sync with current CVS

I have reviewed this patch and it looks good to me. The only
substantive question I have is why gist_point_consistent() uses a
different coding pattern for the box case than it does for the polygon
and circle cases? It's not obvious to me on the face of it why these
aren't consistent.

Emre Hasegeli just pointed out to me that this patch introduced
box_contain_pt() and in doing so used straight C comparison (<= etc)
instead of FPlt() and friends. I would think that that's a bug and
needs to be changed -- but certainly not backpatched, because gist
indexes would/might become corrupt.

This was already fixed for GiST.
See following discussion
/messages/by-id/CAPpHfdvGticGniaj88VCHzHboXJobUhjLm6c09q_Op_u9EoBFg@mail.gmail.com
and
commit
http://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=3c29b196b0ce46662cb9bb7a1f91079fbacbcabb
"Consistent" method of GiST influences only search and can't lead to
corrupt indexes. However, "same" method can lead to corrupt indexes.
However, this is not the reason to not backpatch the changes and preserve
buggy behaviour; this is the reason to recommend reindexing to users. And
it was already backpatched.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#12Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Stefan Keller (#10)
Re: point_ops for GiST

Hi, Stefan!

On Sun, Oct 11, 2015 at 10:00 PM, Stefan Keller <sfkeller@gmail.com> wrote:

Pls. don't misunderstand my questions: They are directed to get an
even more useful spatial data handling of PostgreSQL. I'm working with
PostGIS since years and are interested in any work regarding spatial
types...

Can anyone report use cases or applications of these built-in geometric
types?

Would'nt it be even more useful to concentrate to PostGIS
geometry/geography types and extend BRIN to these types?

Note, that PostGIS is a different project which is maintained by separate
team. PostGIS have its own priorities, development plan etc.
PostgreSQL have to be self-consistent. In particular, it should have
reference implementation of operator classes which extensions can use as
the pattern. This is why it's important to maintain built-in geometric
types.

In short: once we implement it for built-in geometric types, you can ask
PostGIS team to do the same for their geometry/geography.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#13Emre Hasegeli
emre@hasegeli.com
In reply to: Alexander Korotkov (#11)
Re: point_ops for GiST

This was already fixed for GiST.
See following discussion
/messages/by-id/CAPpHfdvGticGniaj88VCHzHboXJobUhjLm6c09q_Op_u9EoBFg@mail.gmail.com
and commit
http://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=3c29b196b0ce46662cb9bb7a1f91079fbacbcabb
"Consistent" method of GiST influences only search and can't lead to corrupt
indexes. However, "same" method can lead to corrupt indexes.
However, this is not the reason to not backpatch the changes and preserve
buggy behaviour; this is the reason to recommend reindexing to users. And it
was already backpatched.

Fixing it on the opclass is not an option for BRIN. We designed BRIN
opclasses extensible using extra SQL level support functions and
operators. It is possible to support point datatype using box vs
point operators. Doing so would lead to wrong results, because point
operators use FP macros, but box_contain_pt() doesn't.

GiST opclass could be more clean and extensible, if we wouldn't have
those macros.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Emre Hasegeli (#13)
Re: point_ops for GiST

On Mon, Oct 12, 2015 at 12:47 PM, Emre Hasegeli <emre@hasegeli.com> wrote:

This was already fixed for GiST.
See following discussion

/messages/by-id/CAPpHfdvGticGniaj88VCHzHboXJobUhjLm6c09q_Op_u9EoBFg@mail.gmail.com

and commit

http://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=3c29b196b0ce46662cb9bb7a1f91079fbacbcabb

"Consistent" method of GiST influences only search and can't lead to

corrupt

indexes. However, "same" method can lead to corrupt indexes.
However, this is not the reason to not backpatch the changes and preserve
buggy behaviour; this is the reason to recommend reindexing to users.

And it

was already backpatched.

Fixing it on the opclass is not an option for BRIN. We designed BRIN
opclasses extensible using extra SQL level support functions and
operators. It is possible to support point datatype using box vs
point operators. Doing so would lead to wrong results, because point
operators use FP macros, but box_contain_pt() doesn't.

You still can workaround this problem in opclass. For instance, you can
assign different strategy number for this case. And call another support
function instead of overlap operator in brin_inclusion_consistent. For
sure, this would be a kluge.

GiST opclass could be more clean and extensible, if we wouldn't have
those macros.

In my opinion it would be cool remove FP macros. I see absolutely no sense
in them. But since it break compatibility it would be quite hard though.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#15Emre Hasegeli
emre@hasegeli.com
In reply to: Alexander Korotkov (#12)
Re: point_ops for GiST

Pls. don't misunderstand my questions: They are directed to get an
even more useful spatial data handling of PostgreSQL. I'm working with
PostGIS since years and are interested in any work regarding spatial
types...

Can anyone report use cases or applications of these built-in geometric
types?

Would'nt it be even more useful to concentrate to PostGIS
geometry/geography types and extend BRIN to these types?

Note, that PostGIS is a different project which is maintained by separate
team. PostGIS have its own priorities, development plan etc.
PostgreSQL have to be self-consistent. In particular, it should have
reference implementation of operator classes which extensions can use as the
pattern. This is why it's important to maintain built-in geometric types.

In short: once we implement it for built-in geometric types, you can ask
PostGIS team to do the same for their geometry/geography.

The problem is that geometric types don't even serve well to this
purpose in their current state. We have to make the operators
consistent to better demonstrate index support of cross type
operators.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16Stefan Keller
sfkeller@gmail.com
In reply to: Alexander Korotkov (#12)
Re: point_ops for GiST

Hi Alexander

Thanks for your succinct reply.
Actually I considered contributing myself for the first time to
PostgreSQL and/or PostGIS.
So, concluding from your explanations there's no big use case behind
build-in geometric types except serving as reference implementation?
I'm still torn over this splitting resources to implement types like
geometry twice.

:Stefan

2015-10-12 11:24 GMT+02:00 Alexander Korotkov <a.korotkov@postgrespro.ru>:

Hi, Stefan!

On Sun, Oct 11, 2015 at 10:00 PM, Stefan Keller <sfkeller@gmail.com> wrote:

Pls. don't misunderstand my questions: They are directed to get an
even more useful spatial data handling of PostgreSQL. I'm working with
PostGIS since years and are interested in any work regarding spatial
types...

Can anyone report use cases or applications of these built-in geometric
types?

Would'nt it be even more useful to concentrate to PostGIS
geometry/geography types and extend BRIN to these types?

Note, that PostGIS is a different project which is maintained by separate
team. PostGIS have its own priorities, development plan etc.
PostgreSQL have to be self-consistent. In particular, it should have
reference implementation of operator classes which extensions can use as the
pattern. This is why it's important to maintain built-in geometric types.

In short: once we implement it for built-in geometric types, you can ask
PostGIS team to do the same for their geometry/geography.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers